Web Api max parameter length - c#-4.0

I have a very simple dto
public class RisRequest
{
public string APIKey { get; set; }
public string Message { get; set; }
}
And a nice easy web api
[HttpPost]
public HttpResponseMessage rad(RisRequest request)
99% of the time this works. but when I hit a request where the Message is longer than the norm (>100,000 characters, and 112kb) then this parameter is null. note the APIKey is still good, my RisRequest object isn't null, but only th eMessage parameter.
I did some googling and tried a bunch of options
as per This link I tried setting the httpconfig buffer
config.Formatters.FormUrlEncodedFormatter.ReadBufferSize = int.MaxValue/10;
I tried the web.config options in this link
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
and
<system.web>
<httpRuntime maxRequestLength="2097152" />
</system.web>
and no luck with either. all other some suggest a variation of the same.
Any ideas where I am going wrong?
Thank

According to Max Parameter length in MVC
this is a windows restriction. in your url, the parameter is part of the path. windows restricts a path segments length.
you should change UrlSegmentMaxLength in regedit.
create a DWORD value in the following registery key
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\HTTP\Parameters
UrlSegmentMaxCount
Maximum number of URL path segments. If zero, the count bounded by the
maximum value of a ULONG.
Valid value range 0 - 16,383

Related

Can I force Azure API Management to return 400 instead of 404 when missing required field?

We have an application that requires some fields to be present. If those fields aren't present we will return a 400 response explaining what is missing in a proper error message. Adding APIM to the mix complicates it a lot it seems. Since APIM know that the field is required it looks like it will short curcuit and return 404 with a generic message instead of our self explanatory message of what is wrong.
Is it a way to turn of this functionality for APIM?
I'm getting the same issue and I endup changing my approach. What I did was to configure it on the Application side and use FluentValidation to make the querystring parameters required. So, my model now looks something like this:
using FluentValidation;
public class UrlQueryParameters
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}
public class UrlQueryParametersValidator : AbstractValidator<UrlQueryParameters>
{
public UrlQueryParametersValidator()
{
RuleFor(o => o.PropertyA)
.NotEmpty()
.WithMessage("The 'PropertyA' parameter was missing or a value was not provided.");
RuleFor(o => o.PropertyB)
.NotEmpty()
.WithMessage("The 'PropertyB' parameter was missing or a value was not provided.");
}
}
The preceding code defines a couple of validation rules with custom messages for PropertyA and PropertyB properties.
Now, enable FluentValidation as the default validation mechanism for our application by adding the following code at ConfigureServices method of Startup.cs file:
public void ConfigureServices(IServiceCollection services) {
// Rest of the code omitted for brevity
services
.AddControllers()
.AddFluentValidation(fv =>
{
fv.DisableDataAnnotationsValidation = true;
// The following line registers ALL public validators in the assembly containing UrlQueryParametersValidator
// There is no need to register additional validators from this assembly.
fv.RegisterValidatorsFromAssemblyContaining<UrlQueryParametersValidator>(lifetime: ServiceLifetime.Singleton);
});
}
At this point, your API endpoints should validate the required parameters from the request and APIM should not short-circuit the request by throwing 404 Not Found when you try to access /api/foo/{id}.
The reason why this works because Swashbuckle doesn't automatically import validation rules from FluentValidation. Meaning, the properties PropertyA and PropertyB won't be marked as required when viewing them in the Swagger UI. This is the downside for this approach as the required querystring parameters from the Swagger UI will not be marked as required which could be confusing to consumers. But to me, returning the correct StatusCode with meaningful message to consumers is more important and that's why I will stick to this workaround for the time being. You could try using the MicroElements.Swashbuckle.FluentValidation to altleast set/marked the parameters as required in the Swagger UI schema. But that's just about it.
I blogged about this it here: Dirty Hack on Making the Required QueryString Params to Work in Azure APIM
At API/Product/Global level policy add on-error section, use choose policy to check if operation was found or not:
<choose>
<when condition="#(context.LastError.Source == "configuration" && context.LastError.Reason == "OperationNotFound")">
<return-response>
<set-status code="400" reason="Bad Request" />
</return-response>
</when>
</choose>

MVC 5 Forms authentication retuns null for User.Identity.Name

Authentication fails to authenticate for forms authentication in my MVC 5 application. Page gets redirected correctly, but User.Identity.IsAuthenticated and User.Identity.Name values are empty.
My webconfig,
<system.web>
<authentication mode="Forms">
<forms cookieless="UseCookies" defaultUrl="~/" loginUrl="~/user/signin" name="MYAPPWeb" timeout="21600" slidingExpiration="true"/>
</authentication>
UserController,
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult SignIn(SignInViewModel user)
{
UserDTO userObj;
using (var services = new ServiceFactory())
{
userObj = services.UserManagement.ValidateLoginDetails(ConfigHelper.EnvironmentString, user.TenantName, user.Username, user.Password);
}
string userID = userObj.UserID.ToString();
//FormsAuthentication.RedirectFromLoginPage(userID, user.RememberMe);
FormsAuthentication.SetAuthCookie(userID.ToString(),true);
FormsAuthentication.RedirectFromLoginPage(userID, false); //DO NOT REMEMBER ME
}
HomeController (Default page)
public ActionResult Index()
{
bool x = User.Identity.IsAuthenticated; //false?
string y = User.Identity.Name; //null?
return View();
}
It looks pretty straight forward, am I missing something? Please help!
Note:
When I create the project I selected windows authentication. It created some Owin authenticaiton related configuration cs files (startup.auth.cs). I have removed them and added the above appsetting entry as it is required to stop loading Owin assemblies.
<add key="owin:AutomaticAppStartup" value="false"/>
If your project has Owin authentication by default, it will remove form authentication from the project.
If you see your web config you may see
<remove name="FormsAuthentication" />
configuration.
Simply remove it.
I had the same problem and it solved the issue.

How to bind string array from FormData when using GET method in ServiceStack?

I have the following DTO which I want to call via GET:
[Route("/documents")]
public class Documents : IReturn<DocumentsResult>
{
public string[] IDs { get; set; }
}
A simple Service:
public DocumentsResult Get(Documents doc)
{
//implementation not relevant
}
When trying to call with many IDs using JsonServiceClient.Get() method, I get BadRequest because the query string is too long.
How can I ensure that the IDs property is bound from FormData?
A GET request can only use the QueryString so does not have FormData. The limit you're hitting is likely an IIS/ASP.NET limit on queryStrings (there are no explicit usage limits in ServiceStack). So you can try and increase the limits on GET requests in your Web.config with:
<system.web>
<httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" />
...
</system.web>
Otherwise your solution is to either use a POST so the request is sent through the request body or batch the requests using a GET into more manageable chunks that doesn't exceed the default limit of 2048 chars.

Orchard - Adding a Zone inside a Part (has a viewmodel)

crosspost: https://orchard.codeplex.com/discussions/461867
Here's the full scenario:
I have an EventItem content item which has an EventItem part containing all the custom fields (intro text, agenda, etc). I have another part attached to EventItem called tracks. The issue now is I want to add a Zone inside tracks so I can render fields from EventItem onto tracks via placement through the dynamic Zone. I know I could pull the data and render it inside the part, but I want it to be flexible and would prefer using placement/zones.
I know dynamic Zones are easy with alternates, like the one below on my Content-EventItem.Detail alternate:
#Display(Model.ImageArea)
However, my part uses a viewmodel so I need to predefine whatever properties/objects I use. I've read this blog as well but it doesn't work, or maybe I missed something:
http://weblogs.asp.net/bleroy/archive/2011/06/30/so-what-are-zones-really.aspx
Here's my full code (omitted irrelevant parts of code):
Track Part Template
#{
Func<dynamic, dynamic> Zone = x => Display(x);
}
<div id="Overview-Tab" class="track-tab">
#Zone(Model.Overview)
</div>
Track Part Viewmodel
public class DisplayAllViewModel
{
//public Shape Overview { get; set; }
public object Overview { get; set; }
public List<TrackItem> Tracks { get; set; }
}
Placement for EventItem
<Match ContentType="EventItem">
<Match DisplayType="Detail">
<Place
Fields_Sections="Overview:1"
Parts_Tracks="Content:2.5.6" />
</Match>
</Match>
The Sections field doesn't display at all when I use the Overview Zone.
Any piece of advise or information would be highly appreciated. Thanks!
This is not how placement and zones work: zones are defined in the Content shape, not in the child shapes below that.
In fact you're making things more difficult than they need to be. If you want to display a field inside your track part template, you can just do so:
#{
var eventItemPart = Model.ContentItem.EventItem;
if (eventItemPart != null) {
#eventItemPart.NameOfTheField.SomePropertyOfThatField
}
}
Alternatively, you may want to read this article: http://weblogs.asp.net/bleroy/archive/2013/02/13/easy-content-templates-for-orchard-take-2.aspx which will show you how to flatten your template structure while maintaining the ability to display the original shapes.
Just add in the part #Display(WorkContext.Layout.Header)

IIS 7.5 forces the http header CacheControl to Private

In my .NET code, I have a custom handler that process Http request and in the ProcessRequest Method calls a custom HttpModule to set Http Cache Headers.
The HttpModule sets the header in the PreSendRequestHeaders method with the following code
HttpCachePolicy cache = response.Cache;
if (cache != null)
{
cache.SetCacheability(HttpCacheability.Public);
cache.SetMaxAge(TimeSpan.FromSeconds(varnishDuration));
response.AppendHeader("Edge-control", String.Concat("!no-store, max-age=", akamaiDuration, "s dca=noop"));
}
In IIS 7.5, with the pool in integrated mode, the CacheControl is forced to private.
Here is what I got :
curl -IXGET -H "Host:myHostName" "http://myServer/mypage"
HTTP/1.1 200 OK
Cache-Control: private
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Edge-control: !no-store, max-age=300s dca=noop
[...]
I don't understand why IIS changes the CacheControl to private.
Here is my webserver section in my web.config :
<pre>
<system.webServer>
<handlers accessPolicy="Read, Script">
<add name="OxygenHandler" verb="*" path="*" type="com.eurosport.oxygen.server.modules.OxygenHandlerFactory, OxygenServerModules" />
</handlers>
<modules runAllManagedModulesForAllRequests="true">
<add name="WebServiceCachingModule" type="com.eurosport.toolkit.WebServiceCachingModule, Eurosport.Toolkit" />
</modules>
</system.webServer>
</pre>
I tried to add SetSlidingExpiration as mentioned here Cache.SetMaxAge not working under IIS, works fine under VS Dev Srv but it did not help.
I've managed to get it working with the following code in my module :
response.Headers.Remove("Cache-Control");
response.AppendHeader("Cache-Control", "public, max-age=" + varnishDuration.ToString()+", s-max-age=" + varnishDuration.ToString());
It looks dirty but it seems that response.CacheControl and response.Cache properties are not used by IIS in integrated mode (or are overriden by some module...)
The default is specified in System.Web.HttpResponse.CacheControl:
/// <devdoc>
/// <para>
/// Provided for ASP compatiblility. Use the <see cref='System.Web.HttpResponse.Cache'/>
/// property instead.
/// </para>
/// </devdoc>
public string CacheControl {
get {
if (_cacheControl == null) {
// the default
return "private";
}
return _cacheControl;
}
While you can override the header through (global) filters, this doesn't work for error pages caused by authentication/authorization. Luckily there's a nice entry point for each request, allowing you to override this default:
// In Global.asax.cs:
protected void Application_BeginRequest()
{
Context.Response.CacheControl = "no-cache";
}
Update: Setting cache-control per above will disable caching of bundles. I'm now using the following workaround. It only changes the page's cacheability when it was not explicitly set. The default value of '6' comes from here:
// In Global.asax.cs:
protected void Application_EndRequest()
{
if ((int)Response.Cache.GetCacheability() == ((int)HttpCacheability.ServerAndPrivate) + 1)
Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
Furthermore when there's an error and the YSOD (yellow error page) is rendered through ReportRuntimeError, the framework will call ClearHeaders and your custom cache-control setting will be overridden. I haven't found a solution for this.

Resources