Skip to content

Commit

Permalink
improve performance for api/types (most of the code in Southwind)
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Jul 23, 2020
1 parent 9a4b7ff commit b47a37c
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 4 deletions.
83 changes: 83 additions & 0 deletions Signum.React/Filters/ETagMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;

namespace Signum.React.Filters
{
public class ETagMiddleware
{
private readonly RequestDelegate _next;

public ETagMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
var response = context.Response;
var originalStream = response.Body;

using (var ms = new MemoryStream())
{
response.Body = ms;

await _next(context);

if (IsEtagSupported(response))
{
string checksum = CalculateChecksum(ms);

response.Headers[HeaderNames.ETag] = checksum;

if (context.Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var etag) && checksum == etag)
{
response.StatusCode = StatusCodes.Status304NotModified;
return;
}
}

ms.Position = 0;
await ms.CopyToAsync(originalStream);
}
}

private static bool IsEtagSupported(HttpResponse response)
{
if (response.StatusCode != StatusCodes.Status200OK)
return false;

// The 20kb length limit is not based in science. Feel free to change
if (response.Body.Length > 10 * 1024 * 1024)
return false;

if (response.Headers.ContainsKey(HeaderNames.ETag))
return false;

return true;
}

private static string CalculateChecksum(MemoryStream ms)
{
using (var algo = SHA1.Create())
{
ms.Position = 0;
byte[] bytes = algo.ComputeHash(ms);
return WebEncoders.Base64UrlEncode(bytes);
}
}
}

public static class ApplicationBuilderExtensions
{
public static void UseETagger(this IApplicationBuilder app)
{
app.UseMiddleware<ETagMiddleware>();
}
}
}
5 changes: 4 additions & 1 deletion Signum.React/Scripts/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { Entity, EntityPack, Lite, ModifiableEntity } from "./Signum.Entities";

Dic.skipClasses.push(React.Component);


export let currentCulture: string | undefined;
export function setCurrentCulture(culture: string | undefined) {
currentCulture = culture;
}

export let currentUser: IUserEntity | undefined;
export function setCurrentUser(user: IUserEntity | undefined) {
Expand Down
11 changes: 8 additions & 3 deletions Signum.React/Scripts/Reflection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Dic } from './Globals';
import { ModifiableEntity, Entity, Lite, MListElement, ModelState, MixinEntity } from './Signum.Entities'; //ONLY TYPES or Cyclic problems in Webpack!
import { ajaxGet } from './Services';
import { MList } from "./Signum.Entities";
import QueryTokenBuilder from './SearchControl/QueryTokenBuilder';
import { AggregateType } from './FindOptions';
import * as AppContext from './AppContext';
import { QueryString } from './QueryString';

export function getEnumInfo(enumTypeName: string, enumId: number): MemberInfo {

Expand Down Expand Up @@ -427,7 +427,12 @@ export function isQueryDefined(queryName: PseudoType | QueryKey): boolean {
}

export function reloadTypes(): Promise<void> {
return ajaxGet<TypeInfoDictionary>({ url: "~/api/reflection/types" })
return ajaxGet<TypeInfoDictionary>({
url: "~/api/reflection/types?" + QueryString.stringify({
user: AppContext.currentUser?.id,
culture: AppContext.currentCulture
})
})
.then(types => {
setTypes(types);
onReloadTypes();
Expand Down

2 comments on commit b47a37c

@olmobrutall
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve api/reflection/types performance in loading animation.

Checkout the latest changes in Southind:

  • signumsoftware/southwind@605ff3b: Simplifies the routing in Startup.cs and fixes the error of URLs starting with api/ being redirected to Home/Index (the SPA root controller).
  • signumsoftware/southwind@f863005: Optimizes api/reflection/type by adding HTTP cache using ETag and HTTP Compression. Very important to improve performance of applications with many entities when logging-in or openning a new tab. Also, I've added a loading animation in Index.cshtml , it's a customized version of one of the spinners in [https://365webresources.com/best-pure-css-loading-spinners/]. Feel free to change it by something that fit better with your design.

image

@MehdyKarimpour
Copy link
Contributor

@MehdyKarimpour MehdyKarimpour commented on b47a37c Jul 23, 2020 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.