I got a webserver in .net working with Nancyfx. I have a route that has to upload an image, this image is sent from a client in json byte64 encoded, along with other attributes. When I try to bind the incoming json with my model, I got the next exception: "Maximum JSON input length has been exceeded."
Something like this:
Post["/Upload", true] = async(_, ctx) =>
{
UploadModel model = null;
model = this.Bind<UploadModel >();
.
.
.
}
I've read that changing the value of "maxJsonLength" in my web.config handles this issue, but when i set a higher value to it, there's no effect:
<scripting>
<webServices>
<jsonSerialization maxJsonLength="50000000"/>
</webServices>
</scripting>
Along with the maxRequestLength:
<httpRuntime targetFramework="4.5" maxRequestLength="1000000"/>
For some smaller pictures (5KB, 50KB) there's no problem in binding, but when I send pictures with sizes of 144KB and up, it gives me the error in concern.
Any thoughts? If I missed some relevant information, just ask me
Never mind guys, I just found the answer:
In the nancy documentation it says "if you encounter the Nancy.Json.JsonSettings.MaxJsonLength Exceeded error because your payload is too high, change that limit in your Bootsrapper ..."
So i did it:
public class Bootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
Nancy.Json.JsonSettings.MaxJsonLength = int.MaxValue;
}
}
Now, no more MaxJsonLength errors, hope this helps to somebody in the future!
Related
I'm running into a 413 issue while trying to send data from my web application (.netfx 4.6.1) to my web api (.net core 3.1). In the code below, I send a list over containing byte data of images along with additional data needed to build a file. The expected output is to return a byte array containing the new file. Unfortunately when sending the request I receive an error: Response status code does not indicate success: 413 (Request Entity Too Large).
The error only seems to occur when the file is large to begin with, which makes sense. The research I've done seems to point to settings in IIS, the main ones being maxAllowedContentLength, maxRequestLength, and uploadReadAheadSize. I've tried increasing these values to ones more suited to this process but nothing seems to work. I've adjusted them for both the web application and the web api, as I was not sure which one was causing the problem.
Where does the problem lie? In the application, the API, or both? Is there an additional setting I'm missing to allow an increased size? Is there an issue with how I'm sending the request? Any help is appreciated.
public static async Task<byte[]> CreatePdfFromImageFilesAsync(List<ImageFile> imageFiles)
{
var list = new List<dynamic>();
foreach (var item in imageFiles)
{
list.Add(new
{
Data = Convert.ToBase64String(item.Bytes),
PageOrder = item.PageOrder,
Rotation = item.Rotation,
Type = "PDF"
});
}
var response = _client.PostAsJsonAsync($"{FileCreatorAPI}/api/files/CreateFileFromMultiple", list).Result;
var result = response.EnsureSuccessStatusCode();
var bytes = await result.Content.ReadAsAsync<byte[]>();
return bytes;
}
Below changes worked for me
// If using Kestrel:
.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
//options.Limits.MaxRequestBodySize = null; --did not worked
options.Limits.MaxRequestBodySize = int.MaxValue;
})
// If using IIS:
.Configure<IISServerOptions>(options =>
{
options.AllowSynchronousIO = true;
//options.MaxRequestBodySize = null;
options.MaxRequestBodySize = int.MaxValue;
});
create web.config file and add following configuration
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
Can you check that attribute https://github.com/aspnet/Announcements/issues/267 ?
Using
[RequestSizeLimit(100_000_000)]
on your controller entry point, or more globally setting it this way:
.UseKestrel(options =>
{
options.Limits.MaxRequestBodySize = null;
EDIT: article from MS: https://dotnet.microsoft.com/download/dotnet-core
I think the problem is on the server. The server is terminating the request because it exceeds it's configured maximum allowable request size.
Which server are you using?
For Nginx users, the directive which determines what the allowable HTTP request size can be is client_max_body_size, the default maximum allowable request size is 1MB.
The limit in Apache is set via the LimitRequestBody directive and defaults to 0 (meaning unlimited) to 2147483647 (2GB).
Check out this article on how you can fix it if you are using any of those two servers.
I have an ASP.NET Web API 2 action method:
[System.Web.Http.HttpPost]
public HttpResponseMessage Create(HttpRequestMessage req)
{
//...
if (success)
return Request.CreateResponse(HttpStatusCode.Created);
return CreateErrorResponse(HttpStatusCode.BadRequest, "you done bad");
}
Until I did "something", upon error it would return http 400 with the custom error text "you done bad". That's the expected result.
It no longer returns the custom text; it just returns the standard "Bad request".
Have been trying to understand what changed to make this happen.
So I tried:
var response = new { message = "you done bad" };
return Request.CreateResponse(HttpStatusCode.BadRequest, response);
Same result.
I then created a new, clean Web API project and I get the result I expect.
How did I break my project?
The problem is related to the CustomErrors configuration in web.config. From #HaukurHaf's answer at Error messages returned from Web API method are omitted in non-dev environment:
Had the same issue. It's indeed because of the custom errors setting.
In a real world scenario, you would definitely want to use a custom
error page in your application, but in order for custom exception
messages to work in the WebAPI you need to disable the custom errors
page.
How to fix this? Luckily, you can use the <location> element in your
web.config to solve this.
Solution:
<!-- General for the application -->
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="YourCustomErrorPage.aspx"/>
</system.web>
<!-- Override it for paths starting with api (your WebAPI) -->
<location path="api">
<system.web>
<customErrors mode="Off" />
</system.web>
</location>
I use this method in my own app, works well.
While I do see that this works, I don't understand why the CustomErrors section breaks it.
You need to change your method as below
[Route("User/GetUserIDCustomMessage")]
[HttpPost]
public HttpResponseMessage GetUserIDCustomMessage(HttpRequestMessage request, int Id)
{
HttpResponseMessage response = null;
if (Id == 1)
{
response = request.CreateResponse(HttpStatusCode.OK);
}
else {
response = request.CreateResponse(HttpStatusCode.BadRequest , "YOu type bad");
}
return response;
}
When I give 1 , it will give me OK message with 200 status code , otherwise it will give 400/Bad Request , with body message 'YOu type bad'
I think you can probably consider creating a instance of HttpResponseMessage and add your custom error message to its Content property.
HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.BadRequest);
msg.Content = new StringContent("you done bad");
return msg;
// or can re-throw it
//throw new HttpResponseException(msg);
Please check the following link for details
https://msdn.microsoft.com/en-us/library/system.net.http.httpresponsemessage(v=vs.118).aspx
I'm "playing" around with custom inbound URL routing and have came across a problem.
When I pass my custom route a URL to examine, that ends in *.+, my class is not fired when i submit the request.
An example URL would be "~/old/windows.html"
When I step through this in the debugger, my RouteBase implementation doesn't fire. If i edit the url that i pass to the constructor of my route to try to match against "~/old/windows", my implemetation is fired as expected.
Again, If i change the url ro examine to "~/old/windows." the problem reoccurs.
My Route Implementation is below :-
public class LegacyRoute : RouteBase
{
private string[] _urls;
public LegacyRoute(string[] targetUrls)
{
_urls = targetUrls;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
string requestedURL = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (_urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase))
{
result = new RouteData(this, new MvcRouteHandler());
result.Values.Add("controller", "Legacy");
result.Values.Add("action","GetLegacyURL");
result.Values.Add("legacyURL", requestedURL);
}
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}
}
In the RoutesConfig file I have registered my route like so :-
routes.MapMvcAttributeRoutes();
routes.Add(new LegacyRoute(new[]{"~/articles/windows.html","~/old/.Net_1.0_Class_Library"}));
Can anyone point out why there is a problem?
By default, the .html extension is not handled by .NET, it is handled by IIS directly. You can override by adding the following section in Web.config under <system.webServer> -
<handlers>
<add name="HtmlFileHandler" path="*.html" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
As pointed out here. The above will route EVERY .html file request to .NET, you might want to be more specific by providing a more complete path if you don't want your routing to handle every .html file.
I've found the problem, and I'm sure this will help out a lot of fellow developers.
The problem is with IIS Express that is running via Visual Studio.
There is a module configured in the applicationhost.config called :-
UrlRoutingModule-4.0
This is how it looks in file :-
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
You need to set the preCondition Parameter to "".
To do this :-
Run you app via Visual Studio
Right click on IIS Express in your system tray, select "Show All Applications"
Click on the project you wish to edit, then click the config URL.
Open the file with Visual Studio, Locate the module and ammend.
Hope this helps anyone else, who ran into a similar problem.
I have an aspx page where I’m allowing a user to upload a file and I want to cap the max file upload size to be 10MB. IIS7, .NET 3.5. I have the following configured in my web.config file:
<location path="foo.aspx">
<system.web>
<!-- maxRequestLength: kbytes, executionTimeout:seconds -->
<httpRuntime maxRequestLength="10240" executionTimeout="120" />
<authorization>
<allow roles="customRole"/>
<!-- Deny everyone else -->
<deny users="*"/>
</authorization>
</system.web>
<system.webServer>
<security>
<requestFiltering>
<!-- maxAllowedContentLength: bytes -->
<requestLimits maxAllowedContentLength="10240000"/>
</requestFiltering>
</security>
<handlers accessPolicy="Read, Script">
<add name="foo" path="foo.aspx" verb="POST"
type="System.Web.UI.PageHandlerFactory"
preCondition="integratedMode" />
</handlers>
</system.webServer>
</location>
I have a custom error handling module that implements IHttpModule. I’ve found that when maxRequestLength is exceeded, HttpApplication.Error does indeed get raised. However when I play with maxAllowedContentLength, the HttpApplication.Error event isn’t being raised and the user gets redirected to a 404.13 page. I've attached with Visual Studio with first chance exceptions turned on nothing is being thrown.
My first thought is to check the header content length in an earlier event – are there recommendations/best practices of where I do this? PostLogRequest? EndRequest?
After looking at the ASP.NET Application Life Cycle Overview for IIS 7.0 and doing my own experimentation, I'm assuming that the request validation is done internally by IIS before any of the events are raised.
It looks like only LogRequest, PostLogRequest, EndRequest, PreSendRequestContent, and PreSendRequestHeaders are raised after the internal validation with this error.
I've decided to attach an event handler to the HttpApplication.EndRequest event in my custom error handler and check for the 404.13 status code on POST and handle as I need it to be handled, which in my case is to redirect to the calling page which will check Server.GetLastError() and display a friendly error to the end user.
private void application_EndRequest(object sender, EventArgs e)
{
HttpRequest request = HttpContext.Current.Request;
HttpResponse response = HttpContext.Current.Response;
if ((request.HttpMethod == "POST") &&
(response.StatusCode == 404 && response.SubStatusCode == 13))
{
// Clear the response header but do not clear errors and
// transfer back to requesting page to handle error
response.ClearHeaders();
HttpContext.Current.Server.Transfer(
request.AppRelativeCurrentExecutionFilePath);
}
}
I'd welcome feedback on this approach and alternatives.
The simplest method is to handle it in the OnError method of page itself.
I think this works only in .NET 4.0, since the WebEventCode property is documented as NEW in .NET 4.0.
protected override void OnError(EventArgs e)
{
Exception err = Server.GetLastError();
if (err is HttpException)
{
if ((err as HttpException).WebEventCode == 3004)
{
Context.Items["error"] = "File exceeded maximum allowed length.";
Server.Transfer( Context.Request.Url.LocalPath );
return;
}
}
base.OnError(e);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!IsPostBack)
{
string error = Context.Items["error"] as string;
if (!string.IsNullOrEmpty( error ))
showErrorMessage( error );
}
}
What I did was:
get the last error with Server.GetLastError
check that it's a "Maximum request length exceeded." error (WebEventCode == 3004).
added a value to Context.Items collections to flag the request as an error
transfer the request back to the page itself with Server.Transfer(Context.Request.Url.LocalPath)
the page's OnLoad method checks for the error flag and displays a message if present
This ensures the error is handled entirely on the requested page, and the page is capable of reporting errors.
Also note that while the browser will eventually receive a proper response, the browser may take its time uploading the entire request before it handles the server's response and displays it. This behavior is probably defined as part of the server/browser interaction in the HTTP protocol, so probably not much can be done about that.
I'm running into some performance issues using a generic handler that implements IHttpAsyncHandler. At its simplest, the handler receives a GET request, and 20 seconds later ends the response after writing '< timeout / >' to the response.
When hammering the .ashx with 10000-20000 simultaneous requests, it fails with 503 server unavailable after precisely 5000 requests. When switching to synchronous mode, and ending the request immediately, the problem goes away.
I've tinkered with a number of settings, yet the only thing I've managed to acheive is lower the request threshold at which this error occurs.
Here's a rundown of the settings I've toyed with:
machine.config:
<configuration>
...
<system.web>
...
<processModel enable="true" requestQueueLimit="10000"/>
...
web.config:
<configuration>
...
<system.web>
...
<httpRuntime enable="true" appRequestQueueLimit="10000"/>
...
IIS Manager > ApplicationPools > Advanced Settings
Queue Length : 65535
Although I can't be sure, it seems like these settings work good and fine if the requests are synchronous, but when async, I can't seem to get beyond exactly 5000 requests before the server starts telling me to go away. If I set things lower (can't remember exactly which setting that would be from the above, but I've tried them all), then the 503 count goes up accordingly, but I can never stop it happening beyond 5000 when under serious load.
It seems that there a a number of settings scattered in a myriad of places that might affect this, but the 5000 seems fairly set in stone. I see here that appRequestQueueLimit cannot exceed 5000, but can find no further info about this, and wonder if this is misinformation.
Is there any kind of "flood-control" setting in IIS that might be limiting a single host to no more than 5000 requests? How can I get IIS to handle more that 5000 concurrent asynchronous requests?
Edit2: Are there any counters or other indicators of which limit might be being exceeded, and how would I investigate further?
Edit: Here's the loadgenerator code:
using System;
using System.Net;
using System.Threading;
namespace HammerTime
{
class Program
{
private static int counter = 0;
static void Main(string[] args)
{
var limit = 5000;
ServicePointManager.DefaultConnectionLimit=limit;
for (int i = 0; i < limit;++i )
{
StartWebRequest(i.ToString());
}
Console.ReadLine();
}
private static void StartWebRequest(string channelId)
{
string uri = "http://spender2008/test/Test.ashx?channel="+channelId;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
request.BeginGetResponse(responseHandler, request);
}
private static void responseHandler(IAsyncResult ar)
{
try
{
HttpWebRequest state = (HttpWebRequest)ar.AsyncState;
HttpWebResponse response = (HttpWebResponse)state.EndGetResponse(ar);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
Console.WriteLine(Interlocked.Increment(ref counter));
}
}
}
}
OK. Fixed... many thanks to this post for clearing up a few details.
To eliminate the 503 errors required 3 different config changes:
machine.config:
<configuration>
...
<system.web>
...
<processModel enable="true" requestQueueLimit="100000"/>
IIS Manager > ApplicationPools > Advanced Settings
Queue Length : 65535
and finally (the missing piece of the puzzle), the command line:
appcmd.exe set config /section:serverRuntime /appConcurrentRequestLimit:100000
The web.config setting mentioned in the main post was irrelevant.
10000 concurrent connections, no problems. Thanks for help!