wvd-templates/diagnostics-sample/src/MSFT.WVD.Diagnostics.Common/Services/DiagnozeService.cs (271 lines of code) (raw):
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using MSFT.WVD.Diagnostics.Common.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace MSFT.WVD.Diagnostics.Common.Services
{
public class DiagnozeService
{
IConfiguration _config;
ILogger _logger;
IMemoryCache _cache;
string _brokerUrl;
public DiagnozeService(IConfiguration configuration, ILoggerFactory logger, IMemoryCache memoryCache)
{
_logger = logger?.CreateLogger<DiagnozeService>() ?? throw new ArgumentNullException(nameof(logger));
_config = configuration ?? throw new ArgumentNullException(nameof(configuration));
_cache = memoryCache ?? throw new ArgumentException(nameof(memoryCache));
_brokerUrl = _config["configurations:RDBROKER_URL"];
if (string.IsNullOrEmpty(_brokerUrl))
{
_logger.LogError("Missing configurations:RDBROKER_URL");
//throw new ConfigurationErrorsException("Missing RDSManagement:RDBROKER_URL");
throw new Exception("Missing configurations:RDBROKER_URL");
}
}
public async Task<List<ConnectionActivity>> GetConnectionActivities(string accessToken, string upn, string tenantGroupName, string tenant, string startDatetime, string endDatetime, string outcome)
{
_logger.LogInformation($"Service call to get connection activities of user {upn} of Tenant {tenant} within tenant group {tenantGroupName} ");
// Here we will add user to the key
var key = new Tuple<string, string, string, string, string, string, string>(nameof(GetConnectionActivities), upn, tenantGroupName, tenant, startDatetime, endDatetime, outcome);
// Try to get from cache first
var result = await _cache.GetOrCreateAsync(key, async entry =>
{
int activityType = (int)ActivityType.Connection;
outcome = outcome == ActivityOutcome.All.ToString() ? null : outcome;
var url = "";
if (outcome == null)
{
url = $"{_brokerUrl}RdsManagement/V1/DiagnosticActivities/TenantGroups/{tenantGroupName}/Tenants/{tenant}?UserName={upn}&StartTime={startDatetime}&EndTime={endDatetime}&ActivityType={activityType}&Detailed=true";//&PageSize=1000&SortField=StartTime&IsDescending=True";
}
else
{
int outcomeVal = (int)Enum.Parse(typeof(ActivityOutcome), outcome);
url = $"{_brokerUrl}RdsManagement/V1/DiagnosticActivities/TenantGroups/{tenantGroupName}/Tenants/{tenant}?UserName={upn}&StartTime={startDatetime}&EndTime={endDatetime}&ActivityType={activityType}&Outcome={outcomeVal}&Detailed=true";// &PageSize=1000&SortField=StartTime&IsDescending=True";
}
var reply = await SendRequest(url, accessToken).ConfigureAwait(false);
// Set cache expiration
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2);
return reply;
}).ConfigureAwait(false);
if (result.StatusCode == HttpStatusCode.OK)
{
var data = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
var arr = (JArray)JsonConvert.DeserializeObject(data);
return ((JArray)arr).Select(item => new ConnectionActivity
{
activityId = (string)item["activityId"],
activityType = (string)item["activityType"],
startTime = item["startTime"].ToString() != null ? Convert.ToDateTime(item["startTime"]) : (DateTime?)null,
endTime = (string)item["endTime"] == null || (string)item["endTime"] == "" ? (DateTime?)null : Convert.ToDateTime(item["endTime"]),
userName = item["userName"].ToString(),
outcome = (string)item["outcome"] == null || (string)item["outcome"] == "" ? "" : Enum.GetName(typeof(ActivityOutcome), (int)item["outcome"]),
// isInternalError = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorInternal"] : null,
// errorMessage = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorMessage"] : null,
//errors= errors.OfType<JObject>().ToList(),
errors = item["errors"].OfType<JObject>().ToList(),
ClientOS = (string)item["details"]["ClientOS"],
ClientIPAddress = item["details"]["ClientIPAddress"].ToString(),
Tenants = (string)item["details"]["Tenants"],
SessionHostName = (string)item["details"]["SessionHostName"],
SessionHostPoolName = (string)item["details"]["SessionHostPoolName"]
}).ToList().OrderByDescending(x=> x.startTime).ToList();
}
else
{
_logger.LogError($"Service call to get connection activities of user {upn} of Tenant {tenant} within tenant group {tenantGroupName} is failed. Error : {result} ");
return new List<ConnectionActivity>() {
new ConnectionActivity()
{
ErrorDetails= new ErrorDetails
{
StatusCode=(int)result.StatusCode,
Message = result.ReasonPhrase.ToString()
}
}
};
}
}
public async Task<List<ManagementActivity>> GetManagementActivities(string accessToken, string upn, string tenantGroupName, string tenant, string startDatetime, string endDatetime, string outcome)
{
_logger.LogInformation($"Service call to get management activities of user {upn} of Tenant {tenant} within tenant group {tenantGroupName} ");
// Here we will add user to the key
var key = new Tuple<string, string, string, string, string, string, string>(nameof(GetManagementActivities), upn, tenantGroupName, tenant, startDatetime, endDatetime, outcome);
// Try to get from cache first
var result = await _cache.GetOrCreateAsync(key, async entry =>
{
int activityType = (int)ActivityType.Management;
outcome = outcome == ActivityOutcome.All.ToString() ? null : outcome;
var url = "";
if (outcome == null)
{
url = $"{_brokerUrl}RdsManagement/V1/DiagnosticActivities/TenantGroups/{tenantGroupName}/Tenants/{tenant}?UserName={upn}&StartTime={startDatetime}&EndTime={endDatetime}&ActivityType={activityType}&Detailed=true";
}
else
{
int outcomeVal = (int)Enum.Parse(typeof(ActivityOutcome), outcome);
url = $"{_brokerUrl}RdsManagement/V1/DiagnosticActivities/TenantGroups/{tenantGroupName}/Tenants/{tenant}?UserName={upn}&StartTime={startDatetime}&EndTime={endDatetime}&ActivityType={activityType}&Outcome={outcomeVal}&Detailed=true";
}
var reply = await SendRequest(url, accessToken).ConfigureAwait(false);
// Set cache expiration
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2);
return reply;
}).ConfigureAwait(false);
if (result.StatusCode == HttpStatusCode.OK)
{
var data = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
var arr = (JArray)JsonConvert.DeserializeObject(data);
return ((JArray)arr).Select(item => new ManagementActivity
{
activityId = (string)item["activityId"],
activityType = (string)item["activityType"],
startTime = item["startTime"].ToString() != null ? Convert.ToDateTime(item["startTime"]) : (DateTime?)null,
endTime = (string)item["endTime"] == null || (string)item["endTime"] == "" ? (DateTime?)null : Convert.ToDateTime(item["endTime"]),
userName = (string)item["userName"],
outcome = (string)item["outcome"] == null || (string)item["outcome"] == "" ? "" : Enum.GetName(typeof(ActivityOutcome), (int)item["outcome"]),
isInternalError = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorInternal"] : null,
errorMessage = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorMessage"] : null,
ObjectsCreated = (string)item["ObjectsCreated"] == null || (string)item["ObjectsCreated"] == "" ? 0 : (int)item["ObjectsCreated"],
ObjectsDeleted = (string)item["ObjectsDeleted"] == null || (string)item["ObjectsDeleted"] == "" ? 0 : (int)item["ObjectsDeleted"],
ObjectsFetched = (string)item["ObjectsFetched"] == null || (string)item["ObjectsFetched"] == "" ? 0 : (int)item["ObjectsFetched"],
ObjectsUpdated = (string)item["ObjectsUpdated"] == null || (string)item["ObjectsUpdated"] == "" ? 0 : (int)item["ObjectsUpdated"],
Tenants = (string)item["details"]["Tenants"]
}).ToList();
}
else
{
_logger.LogError($"Service call to get management activities of user {upn} of Tenant {tenant} within tenant group {tenantGroupName} is failed. Error : {result} ");
return new List<ManagementActivity>() {
new ManagementActivity()
{
ErrorDetails= new ErrorDetails
{
StatusCode=(int)result.StatusCode,
Message = result.ReasonPhrase.ToString()
}
}
};
}
}
public async Task<List<FeedActivity>> GetFeedActivities(string accessToken, string upn, string tenantGroupName, string tenant, string startDatetime, string endDatetime, string outcome)
{
_logger.LogInformation($"Service call to get feed activities of user {upn} of Tenant {tenant} within tenant group {tenantGroupName} ");
// Here we will add user to the key
var key = new Tuple<string, string, string, string, string, string, string>(nameof(GetFeedActivities), upn, tenantGroupName, tenant, startDatetime, endDatetime, outcome);
// Try to get from cache first
var result = await _cache.GetOrCreateAsync(key, async entry =>
{
int activityType = (int)ActivityType.Feed;
outcome = outcome == ActivityOutcome.All.ToString() ? null : outcome;
var url = "";
if (outcome == null)
{
url = $"{_brokerUrl}RdsManagement/V1/DiagnosticActivities/TenantGroups/{tenantGroupName}/Tenants/{tenant}?UserName={upn}&StartTime={startDatetime}&EndTime={endDatetime}&ActivityType={activityType}&Detailed=true";
}
else
{
int outcomeVal = (int)Enum.Parse(typeof(ActivityOutcome), outcome);
url = $"{_brokerUrl}RdsManagement/V1/DiagnosticActivities/TenantGroups/{tenantGroupName}/Tenants/{tenant}?UserName={upn}&StartTime={startDatetime}&EndTime={endDatetime}&ActivityType={activityType}&Outcome={outcomeVal}&Detailed=true";
}
var reply = await SendRequest(url, accessToken).ConfigureAwait(false);
// Set cache expiration
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2);
return reply;
}).ConfigureAwait(false);
if (result.StatusCode == HttpStatusCode.OK)
{
var data = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
var arr = (JArray)JsonConvert.DeserializeObject(data);
return ((JArray)arr).Select(item => new FeedActivity
{
activityId = (string)item["activityId"],
activityType = (string)item["activityType"],
startTime = item["startTime"].ToString() != null ? Convert.ToDateTime(item["startTime"]) : (DateTime?)null,
endTime = (string)item["endTime"] == null || (string)item["endTime"] == "" ? (DateTime?)null : Convert.ToDateTime(item["endTime"]),
userName = (string)item["userName"],
outcome = (string)item["outcome"] == null || (string)item["outcome"] == "" ? "" : Enum.GetName(typeof(ActivityOutcome), (int)item["outcome"]),
isInternalError = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorInternal"] : null,
errorMessage = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorMessage"] : null,
ClientOS = (string)item["details"]["ClientOS"],
ClientIPAddress = item["details"]["ClientIPAddress"].ToString()
}).ToList();
}
else
{
_logger.LogError($"Service call to get feed activities of user {upn} of Tenant {tenant} within tenant group {tenantGroupName} is failed. Error : {result} ");
return new List<FeedActivity>() {
new FeedActivity()
{
ErrorDetails= new ErrorDetails
{
StatusCode=(int)result.StatusCode,
Message = result.ReasonPhrase.ToString()
}
}
};
}
}
public async Task<List<ConnectionActivity>> GetActivityHostDetails(string accessToken, string tenantGroupName, string tenant, string activityId)
{
_logger.LogInformation($"Service call to get activity details based on activityId {activityId}");
// Here we will add user to the key
var key = new Tuple<string, string, string, string>(nameof(GetActivityHostDetails), tenantGroupName, tenant, activityId);
// Try to get from cache first
var result = await _cache.GetOrCreateAsync(key, async entry =>
{
var url = "";
url = $"{_brokerUrl}RdsManagement/V1/DiagnosticActivities/TenantGroups/{tenantGroupName}/Tenants/{tenant}?ActivityId={activityId}&Detailed=true";
var reply = await SendRequest(url, accessToken).ConfigureAwait(false);
// Set cache expiration
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2);
return reply;
}).ConfigureAwait(false);
if (result.StatusCode == HttpStatusCode.OK)
{
var data = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
var arr = (JArray)JsonConvert.DeserializeObject(data);
return ((JArray)arr).Select(item => new ConnectionActivity
{
activityId = (string)item["activityId"],
activityType = (string)item["activityType"],
startTime = item["startTime"].ToString() != null ? Convert.ToDateTime(item["startTime"]) : (DateTime?)null,
endTime = (string)item["endTime"] == null || (string)item["endTime"] == "" ? (DateTime?)null : Convert.ToDateTime(item["endTime"]),
userName = item["userName"].ToString(),
outcome = (string)item["outcome"] == null || (string)item["outcome"] == "" ? "" : Enum.GetName(typeof(ActivityOutcome), (int)item["outcome"]),
//isInternalError = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorInternal"] : null,
// errorMessage = item["errors"].ToArray().Count() > 0 ? (string)item["errors"][0]["errorMessage"] : null,
errors= item["errors"].OfType<JObject>().ToList(),
ClientOS = (string)item["details"]["ClientOS"],
ClientIPAddress = item["details"]["ClientIPAddress"].ToString(),
Tenants = (string)item["details"]["Tenants"],
SessionHostName = (string)item["details"]["SessionHostName"],
SessionHostPoolName = (string)item["details"]["SessionHostPoolName"]
}).ToList();
}
else
{
_logger.LogError($"Service call to get activity details based on activityId {activityId} is failed. Error : {result} ");
return new List<ConnectionActivity>() {
new ConnectionActivity()
{
ErrorDetails= new ErrorDetails
{
StatusCode=(int)result.StatusCode,
Message = result.ReasonPhrase.ToString()
}
}
};
}
}
private async Task<HttpResponseMessage> SendRequest(string url, string accessToken)
{
return await Request(HttpMethod.Get, url, accessToken);
}
private async Task<HttpResponseMessage> Request(HttpMethod httpMethod, string url, string accessToken)
{
var activityId = Guid.NewGuid().ToString();
_logger.LogInformation($"Sending RDS Management request to {url}. ActivityId:{activityId}");
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-ms-correlation-id", activityId);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpRequestMessage request = new HttpRequestMessage(httpMethod, url);
HttpResponseMessage response = await client.SendAsync(request);
_logger.LogInformation($"Received response from ActivityId:{activityId} Status:{response.StatusCode}");
return response;
}
}
}
}