Api: added CustomJsonOptionsWrapper. optimization

This commit is contained in:
pavelbannov 2019-09-03 12:31:15 +03:00
parent f9329d81ba
commit a26d8d24ce
15 changed files with 111 additions and 109 deletions

View File

@ -7,6 +7,10 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview8.19405.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\web\ASC.Web.Core\ASC.Web.Core.csproj" />
<ProjectReference Include="..\ASC.Common\ASC.Common.csproj" />

View File

@ -25,7 +25,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ASC.Core;
using ASC.Core.Tenants;
@ -36,7 +35,6 @@ namespace ASC.Api.Core
public class ApiContext : ICloneable
{
public HttpContext HttpContext { get; set; }
private IQueryCollection Query { get; set; }
private Tenant tenant;
public Tenant Tenant { get { return tenant ?? (tenant = CoreContext.TenantManager.GetCurrentTenant(HttpContext)); } }
@ -45,42 +43,38 @@ namespace ASC.Api.Core
if (httpContext == null) return;
HttpContext = httpContext;
if (HttpContext.Request.QueryString != null)
{
Query = HttpContext.Request.Query;
}
Count = 0;
var query = HttpContext.Request.Query;
//Try parse values
var count = GetRequestValue("count");
var count = query.GetRequestValue("count");
if (!string.IsNullOrEmpty(count) && ulong.TryParse(count, out var countParsed))
{
//Count specified and valid
Count = (long)countParsed;
}
var startIndex = GetRequestValue("startIndex");
var startIndex = query.GetRequestValue("startIndex");
if (startIndex != null && long.TryParse(startIndex, out var startIndexParsed))
{
StartIndex = Math.Max(0, startIndexParsed);
SpecifiedStartIndex = StartIndex;
}
var sortOrder = GetRequestValue("sortOrder");
var sortOrder = query.GetRequestValue("sortOrder");
if ("descending".Equals(sortOrder))
{
SortDescending = true;
}
FilterToType = GetRequestValue("type");
SortBy = GetRequestValue("sortBy");
FilterBy = GetRequestValue("filterBy");
FilterOp = GetRequestValue("filterOp");
FilterValue = GetRequestValue("filterValue");
FilterValues = GetRequestArray("filterValue");
Fields = GetRequestArray("fields");
FilterToType = query.GetRequestValue("type");
SortBy = query.GetRequestValue("sortBy");
FilterBy = query.GetRequestValue("filterBy");
FilterOp = query.GetRequestValue("filterOp");
FilterValue = query.GetRequestValue("filterValue");
FilterValues = query.GetRequestArray("filterValue");
Fields = query.GetRequestArray("fields");
var updatedSince = GetRequestValue("updatedSince");
var updatedSince = query.GetRequestValue("updatedSince");
if (updatedSince != null)
{
UpdatedSince = Convert.ToDateTime(updatedSince);
@ -89,35 +83,6 @@ namespace ASC.Api.Core
public string[] Fields { get; set; }
private string[] GetRequestArray(string key)
{
if (Query != null)
{
var values = Query[key + "[]"];
if (values.Count > 0)
return values;
values = Query[key];
if (values.Count > 0)
{
if (values.Count == 1) //If it's only one element
{
//Try split
if (!string.IsNullOrEmpty(values[0]))
return values[0].Split(',');
}
return values;
}
}
return null;
}
public string GetRequestValue(string key)
{
var reqArray = GetRequestArray(key);
return reqArray?.FirstOrDefault();
}
public string[] FilterValues { get; set; }
/// <summary>
@ -180,8 +145,6 @@ namespace ASC.Api.Core
public bool FromCache { get; set; }
private readonly List<Type> _knowntype = new List<Type>();
internal long SpecifiedCount { get; private set; }
/// <summary>
@ -228,25 +191,10 @@ namespace ASC.Api.Core
}
}
}
public void RegisterType(Type type)
public ApiContext SetCount(int count)
{
if (!_knowntype.Contains(type))
{
_knowntype.Add(type);
}
}
public void RegisterTypes(IEnumerable<Type> types)
{
_knowntype.AddRange(types);
}
internal IEnumerable<Type> GetKnownTypes()
{
return _knowntype.Distinct();
HttpContext.Items[nameof(Count)] = count;
return this;
}
public object Clone()
@ -268,6 +216,38 @@ namespace ASC.Api.Core
}
}
public static class QueryExtension
{
internal static string[] GetRequestArray(this IQueryCollection query, string key)
{
if (query != null)
{
var values = query[key + "[]"];
if (values.Count > 0)
return values;
values = query[key];
if (values.Count > 0)
{
if (values.Count == 1) //If it's only one element
{
//Try split
if (!string.IsNullOrEmpty(values[0]))
return values[0].Split(',');
}
return values;
}
}
return null;
}
public static string GetRequestValue(this IQueryCollection query, string key)
{
var reqArray = query.GetRequestArray(key);
return reqArray?.FirstOrDefault();
}
}
public static class ApiContextExtension
{
public static bool Check(this ApiContext context, string field)

View File

@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace ASC.Api.Core.Core
{
public class CustomJsonOptionsWrapper : IConfigureOptions<MvcNewtonsoftJsonOptions>
{
readonly IHttpContextAccessor ServiceProvider;
public CustomJsonOptionsWrapper(IHttpContextAccessor serviceProvider)
{
ServiceProvider = serviceProvider;
}
public void Configure(MvcNewtonsoftJsonOptions options)
{
options.SerializerSettings.ContractResolver = new ResponseContractResolver(ServiceProvider);
}
}
}

View File

@ -29,8 +29,6 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
@ -38,9 +36,9 @@ namespace ASC.Api.Core
{
public class ResponseContractResolver : DefaultContractResolver
{
public ServiceProvider Services { get; }
public IHttpContextAccessor Services { get; }
public ResponseContractResolver(ServiceProvider services)
public ResponseContractResolver(IHttpContextAccessor services)
{
Services = services;
NamingStrategy = new CamelCaseNamingStrategy
@ -82,11 +80,11 @@ namespace ASC.Api.Core
}
public class JsonStringConverter : JsonConverter
{
public ServiceProvider Services { get; }
public IHttpContextAccessor HttpContextAccessor { get; }
public JsonStringConverter(ServiceProvider services)
public JsonStringConverter(IHttpContextAccessor httpContextAccessor)
{
Services = services;
HttpContextAccessor = httpContextAccessor;
}
public override bool CanConvert(Type objectType)
@ -101,8 +99,7 @@ namespace ASC.Api.Core
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var httpContext = new ApiContext(Services.GetService<IHttpContextAccessor>().HttpContext);
var fields = httpContext.Fields;
var fields = HttpContextAccessor.HttpContext.Request.Query.GetRequestArray("fields");
if (fields != null)
{

View File

@ -57,27 +57,34 @@ namespace ASC.Api.Core.Middleware
[DataMember(EmitDefaultValue = false, Order = 3)]
public object Response { get; set; }
protected internal SuccessApiResponse(HttpStatusCode statusCode, object response, long? total = null) : base(statusCode)
protected internal SuccessApiResponse(HttpStatusCode statusCode, object response, long? total = null, int? count = null) : base(statusCode)
{
Status = 0;
Response = response;
Total = total;
if (response is List<object> list)
if (count.HasValue)
{
Count = list.Count;
}
else if (response is IEnumerable<object> collection)
{
Count = collection.Count();
}
else if (response == null)
{
Count = 0;
Count = count;
}
else
{
Count = 1;
if (response is List<object> list)
{
Count = list.Count;
}
else if (response is IEnumerable<object> collection)
{
Count = collection.Count();
}
else if (response == null)
{
Count = 0;
}
else
{
Count = 1;
}
}
}
}

View File

@ -19,7 +19,8 @@ namespace ASC.Api.Core.Middleware
if (context.Result is ObjectResult result)
{
context.HttpContext.Items.TryGetValue("TotalCount", out var total);
result.Value = new SuccessApiResponse((HttpStatusCode)context.HttpContext.Response.StatusCode, result.Value, (long?)total);
context.HttpContext.Items.TryGetValue("Count", out var count);
result.Value = new SuccessApiResponse((HttpStatusCode)context.HttpContext.Response.StatusCode, result.Value, (long?)total, (int?)count);
}
base.OnResultExecuting(context);

View File

@ -91,7 +91,7 @@ namespace ASC.Core.Caching
}
}
public IEnumerable<UserInfo> GetUsers(int tenant, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total)
public List<UserInfo> GetUsers(int tenant, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total)
{
return service.GetUsers(tenant, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, text, sortBy, sortOrderAsc, limit, offset, out total);
}

View File

@ -93,7 +93,7 @@ namespace ASC.Core
return users.ToArray();
}
public IEnumerable<UserInfo> GetUsers(int tenantId, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total)
public List<UserInfo> GetUsers(int tenantId, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total)
{
return userService.GetUsers(tenantId, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, text, sortBy, sortOrderAsc, limit, offset, out total);
}

View File

@ -34,7 +34,7 @@ namespace ASC.Core
{
IDictionary<Guid, UserInfo> GetUsers(int tenant, DateTime from);
IEnumerable<UserInfo> GetUsers(int tenant, bool isAdmin,
List<UserInfo> GetUsers(int tenant, bool isAdmin,
EmployeeStatus? employeeStatus,
List<List<Guid>> includeGroups,
List<Guid> excludeGroups,

View File

@ -50,7 +50,7 @@ namespace ASC.Core.Data
return ExecList(q).ConvertAll(ToUser).ToDictionary(u => u.ID);
}
public IEnumerable<UserInfo> GetUsers(int tenant, bool isAdmin,
public List<UserInfo> GetUsers(int tenant, bool isAdmin,
EmployeeStatus? employeeStatus,
List<List<Guid>> includeGroups,
List<Guid> excludeGroups,

View File

@ -16,10 +16,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<Optimize>false</Optimize>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview8.19405.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ASC.Api.Core\ASC.Api.Core.csproj" />

View File

@ -308,7 +308,8 @@ namespace ASC.Employee.Core.Controllers
var users = CoreContext.UserManager.GetUsers(Tenant.TenantId, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, ApiContext.FilterValue, ApiContext.SortBy, !ApiContext.SortDescending, ApiContext.Count, ApiContext.StartIndex, out var total);
ApiContext.SetTotalCount(total);
ApiContext.SetTotalCount(total)
.SetCount(users.Count);
return users;
}

View File

@ -1,4 +1,3 @@
using ASC.Api.Core;
using ASC.Api.Core.Core;
using ASC.Api.Core.Middleware;
@ -24,6 +23,7 @@ using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace ASC.People
{
@ -43,12 +43,10 @@ namespace ASC.People
services.AddHttpContextAccessor();
services.AddControllers()
.AddNewtonsoftJson(s =>
{
s.SerializerSettings.ContractResolver = new ResponseContractResolver(services.BuildServiceProvider());
})
.AddNewtonsoftJson()
.AddXmlSerializerFormatters();
services.AddTransient<IConfigureOptions<MvcNewtonsoftJsonOptions>, CustomJsonOptionsWrapper>();
services.AddMemoryCache();

View File

@ -19,7 +19,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview8.19405.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0-preview8.19405.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0-preview8-19413-06" />
</ItemGroup>

View File

@ -10,6 +10,7 @@ using ASC.Data.Storage.Configuration;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Studio.Core.Notify;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
@ -22,6 +23,7 @@ using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace ASC.Web.Api
{
@ -39,13 +41,11 @@ namespace ASC.Web.Api
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddNewtonsoftJson(s =>
{
s.SerializerSettings.ContractResolver = new ResponseContractResolver(services.BuildServiceProvider());
s.UseCamelCasing(true);
})
.AddNewtonsoftJson()
.AddXmlSerializerFormatters();
services.AddTransient<IConfigureOptions<MvcNewtonsoftJsonOptions>, CustomJsonOptionsWrapper>();
services.AddMemoryCache();
services.AddDistributedMemoryCache();