Strange behavior about request size limit in Abp web api - file-upload

In .Net Core Project, we could set global request size limit :
int sizeLimit = 200000;
services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = sizeLimit;
});
services.Configure<FormOptions>(x => x.MultipartBodyLengthLimit = sizeLimit);
Then do more strictly request size limit by filter :
[Route("[controller]")]
public class TestApiController : Controller
{
[HttpPost]
[RequestSizeLimit(100_000)]
[RequestFormLimits(MultipartBodyLengthLimit = 100_000)]
public bool Post(IFormFile file)
{
return true;
}
}
But, in the Abp Project, strange situations:
(whether a common web api controller or a dynamic web api controller)
upload a 150,000 bytes file
global limit: 200,000; filter limit: 100,000 => will pass (confuse, cause it should be rejected)
global limit: 100,000; filter limit: 200,000 => will pass
if upload a file beyond 200,000 bytes => will be rejected
Is that a bug or i miss something i should set in the project?
ABP Framework version: abp.io v4.3.0
Framework version: .Net 5
======================== Renew 2022/04/10 ========================
After setting log level i found warning logs even in happy case, uploading a very small size file.
2022-04-10 08:14:49.299 +08:00 [WRN] A request body size limit could not be applied. The IHttpRequestBodySizeFeature for the server is read-only.
2022-04-10 08:14:49.299 +08:00 [WRN] Unable to apply configured form options since the request form has already been read.

Related

Check if request is made to Razor Page

How can I check within middleware code if current request is made to Razor Page not to any other resource (static file, or API)?
All my APIs are located within api folder, so if (!context.Request.Path.StartsWithSegments("/api")) {} filters out APIs, but that will not work for static content as these files and libraries are placed within number of folders what results in number of URL segments.
Could not find any relevant property in context.
First step - place the middleware after app.UseRouting(). Any request for a static file will never reach your middleware because the static files middleware will short circuit the request. Also, after this point, the routing middleware will have selected the endpoint and populated the endpoint metadata. Then you can test the endpoint metadata collection to see if it includes PageRouteMetaData, which tells you that this is a Razor page route:
app.Use((context, next) => {
var endpoint = context.GetEndpoint();
if (endpoint != null)
{
foreach(var md in endpoint.Metadata)
{
if( md is PageRouteMetadata)
{
// this is a page route
}
}
}
return next(context);
});

Integrate MiniProfiler with .NetCore 3.1

I want to integrate MiniProfiler is a WebApi or View /XX/results-index.
The WebApi is authenticated with Bearer Tokens. I only want Group Users in Active Directory can see the results, but I don't get it.
I have this code in ServicesCollection:
services.AddMiniProfiler(options =>
{
options.RouteBasePath = "/profiler";
options.ResultsAuthorizeAsync = async request => await GetAuthorization(request); }).AddEntityFramework();
private static async Task<bool> GetAuthorization(HttpRequest request)
{
// var user = request.HttpContext.User.Identity.Name; --> Is null
return true;
}
In Configure Method in StartUp:
app.UseSwagger().UseSwaggerUI(options =>
{
options.SwaggerEndpoint($"/swagger/v1/swagger.json", $"{env.ApplicationName} V1");
options.OAuthClientId("TestApiswaggerui");
options.OAuthAppName("TestApi Swagger UI");
options.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream(
"TestApi.SwaggerMiniProfiler.html");
})
.UseMiniProfiler();
I want to see mini profiler information through some options:
http://localhost:5050/profiler/results-index --> Show the list methods called
http://localhost:5050/swagger/index.html --> Show the MiniProfiler in the same page
Environment:
.NET Core version: 3.1
MiniProfiler version: MiniProfiler.AspNetCore.Mvc v.4.2.1
Operative system: Windows 10
The piece you're probably missing here is that MiniProfiler shows your results. What's "you" is determined by the UserIdProvider option. When recording and viewing profiles, ensure that these are the same "user ID" (defaults to IP address). It looks like this in options:
services.AddMiniProfiler(options =>
{
options.UserIdProvider = request => ConsistentUserId(request);
});
If your swagger has zero server-side processing at all (e.g. it does not include the MiniProfiler <script> tag from .RenderInludes() or the <mini-profiler /> tag helper, then the issue isn't viewing the profiles so much as not even attempting to view. There are some ideas I have around a static tag without profiles to currently view, but I do not know how to get them into Swagger in it's generation phase (just not familiar enough). Note that it's a blatant hack, but you could work around the issue at the moment with a manual script tag. You'll want to follow https://github.com/MiniProfiler/dotnet/issues/326 for this.
I just want to leave the option of having the traces read for that group from the active directory:
services.AddMiniProfiler(options =>
{
// (Optional) Path to use for profiler URLs, default is /mini-profiler-resources
options.RouteBasePath = "/profiler";
options.ColorScheme = StackExchange.Profiling.ColorScheme.Light;
options.PopupRenderPosition = StackExchange.Profiling.RenderPosition.BottomLeft;
options.PopupShowTimeWithChildren = true;
options.PopupShowTrivial = true;
options.ShouldProfile = ShowProfile;
options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
options.ResultsAuthorize = request => request.HttpContext.User.IsInRole("S-INFORMATICA");
})
.AddEntityFramework();

HTTPClient intermittently locking up server

I have a .NET Core 2.2 app which has a controller acting as a proxy to my APIs.
JS makes a fetch to the proxy, proxy forwards call onto API's and returns response.
I am experiencing intermittent lock ups on the proxy app when its awaiting the response from the HttpClient. When this happens it locks up the entire server. No more requests will be processed.
According to the logs of the API that is being proxied to it is returning fine.
To reproduce this is i have to make 100+ requests in a loop on the client through the proxy. Then i have to reload the page multiple times, reloading it whilst the 100 requests are in flight. It usually takes around 5 hits before things start slowing down.
The proxy will lock up waiting for an awaited request to resolve. Sometimes it comes back after a 4 - 5 second delay, other times after a minuet. Most of the time i haven't waited longer then 10 min before giving up and killing the proxy.
I've distilled the code down to the following block that will reproduce the issue.
I believe im following best practices, its async all the way down, im using IHttpClientFactory to enable sharing of HttpClient instances, im implementing using where i believe it is required.
The implementation was based on this: https://github.com/aspnet/AspLabs/tree/master/src/Proxy
I'm hoping im making a rather obvious mistake that others with more experience can pin point!
Any help would be greatly appreciated.
namespace Controllers
{
[Route("/proxy")]
public class ProxyController : Controller
{
private readonly IHttpClientFactory _factory;
public ProxyController(IHttpClientFactory factory)
{
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
[HttpGet]
[Route("api")]
async public Task ProxyApi(CancellationToken requestAborted)
{
// Build API specific URI
var uri = new Uri("");
// Get headers frpm request
var headers = Request.Headers.ToDictionary(x => x.Key, y => y.Value);
headers.Add(HeaderNames.Authorization, $"Bearer {await HttpContext.GetTokenAsync("access_token")}");
// Build proxy request method. This is within a service
var message = new HttpRequestMessage();
foreach(var header in headers) {
message.Headers.Add(header.Key, header.Value.ToArray());
}
message.RequestUri = uri;
message.Headers.Host = uri.Authority;
message.Method = new HttpMethod(Request.Method);
requestAborted.ThrowIfCancellationRequested();
// Generate client and issue request
using(message)
using(var client = _factory.CreateClient())
// **Always hangs here when it does hang**
using(var result = await client.SendAsync(message, requestAborted).ConfigureAwait(false))
{
// Appy data from request onto response - Again this is within a service
Response.StatusCode = (int)result.StatusCode;
foreach (var header in result.Headers)
{
Response.Headers[header.Key] = header.Value.ToArray();
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
Response.Headers.Remove("transfer-encoding");
requestAborted.ThrowIfCancellationRequested();
using (var responseStream = await result.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(responseStream, 81920);
}
}
}
}
}
EDIT
So modified the code to remove the usings and return the proxied response directly as a string instead of streaming and still getting the same issues.
When running netstat i do see a lot of logs for the url of the proxied API.
4 rows mention the IP of the API being proxied to, probably about another 20 rows mentions the IP of the proxy site. Those numbers dont seem odd to me but i don't have much experience using netstat (first time ive ever fired it up).
Also i have left the proxy running for about 20 min. Its it technically still alive. Responses are coming back. Just taking a very long time between the API being proxied to returning data and the HttpClient resolving. However it wont service any new requests, they just sit there hanging.

How to cache static content using ASP.NET 5 and MVC 6?

This was previously achieved by adding some configuration to the web.config file, but now this file is to be extinguished.
I was expecting to find some methods or properties in the middleware declaration, but I haven't found:
app.UseStaticFiles();
So, which is now the procedure to cache static content as images, scripts, etc.?
Is there another middleware to do this or is this feature not implemented yet in MVC 6?
I'm looking for a way to add the cache-control, expires, etc. headers to the static content.
It is all about Middleware with AspNet Core;
Add the following to your Configure method in the Startup.cs file
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Content-encoding", "gzip");
context.Response.Body = new System.IO.Compression.GZipStream(context.Response.Body,
System.IO.Compression.CompressionMode.Compress);
await next();
await context.Response.Body.FlushAsync();
});
By the way for caching you would add this to the ConfigureServices method
services.AddMvc(options =>
{
options.CacheProfiles.Add("Default",
new CacheProfile()
{
Duration = 60
});
options.CacheProfiles.Add("Never",
new CacheProfile()
{
Location = ResponseCacheLocation.None,
NoStore = true
});
});
And decorate the control with
[ResponseCache(CacheProfileName = "Default")]
public class HomeController : Controller
{
...
Your title says compress, but your question body says cache. I'll assume you mean both.
Minification of css/javascript is already handled by the grunt task runner on publish. Caching and compression outside this seem like something a webserver is more suited to, rather than the application layer, so here's a great article that details the config for nginx to manage caching and compression for kestrel.
If you're using IIS, you can configure caching and compression directly on it, here's a tutorial. Considering the previous versions of MVC configured this functionality in web.config\system.Webserver which basically sets IIS config values, you can likely still use a web.config for the purposes of configuring IIS (only).

How To Disable "Read" Request Cache In Kendo UI Data Source

I'm using ASP.NET MVC Wrapper in MVC4 application.
Everything works fine besides one specific issue:
I defined a datasource for Kendo UI Grid, and when the view loads, the read action is being called as expected.
However, when the page reloads, "read" request gets a response with 304 result.
How can I disable the cache through data source configuration?
You are able to set the 'cache' attribute in your Kendo dataSource to false, which apparently (NOTE: I have not tested this) will force the requested page(s) to be newly fetched on every request.
Setting cache to false appends a "_=[TIMESTAMP]" parameter to the request, which if necessary can be parsed on the server/controller side to avoid server-side cache operations.
Note too that you can specify cache behavior per Kendo transport operation (ie, it can be at the level of CRUD operations or for the whole transport).
See here: http://docs.kendoui.com/api/framework/datasource#configuration-transport.read.cache-Boolean
Code:
transport: {
read: {
cache: false
}
}
.Read(read => read
.Action("Action", "Controller", new { area = "Area" })
.Type(HttpVerbs.Post))
You can try decorating on server side controller's action that loads view with
[OutputCache(Duration = 0, NoStore = true)]
attribute, for instance
public class OrdersController : Controller
{
[httpGet]
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult Orders(string userId)
{
// your code
return View(viewModel);
}
}
NoStore - A Boolean value that determines whether to prevent secondary storage of sensitive information
Duration - The time, in seconds, that the page or user control is cached. Setting this attribute on a page or user control establishes an expiration policy for HTTP responses from the object and will automatically cache the page or user control output.
Can't be controller through the Datasource config. You will have to apply an attribute to the Read method on the controller to prevent caching.
An alternative would be to apply the [HttpPost] attribute to your controller method. Then configure the datasource to NOT use the GET method, in which case it will default to use the POST method.