I'm having an issue and I think it's with the WSFederationAuthenticationModule. I'm using WIF along with WebAPI and I'm trying to upload large files through the web api service. I am trying to use bufferless streams for the file upload so I followed the
instructions here:
The methodology for enabling bufferless streams on WebAPI is to inherit from WebHostBufferPolicySelector and return true for 'UseBufferedInputStream'. And then add this at startup:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHostBufferPolicySelector), new NoBufferPolicySelector());
This was working fine until I added WSFederationAuthenticationModule. When WSFederationAuthenticationModule is present in my web.config I get the exception at the bottom of this post. Is WSFam already opening the input stream and preventing HttpRequest.GetBufferlessInputStream from working?
I'm not sure if this is an issue with WSFam or HttpRequest.GetBufferlessInputStream().
Exception:
This method or property is not supported after HttpRequest.Form, Files, InputStream, or BinaryRead has been invoked.
at System.Web.HttpRequest.GetInputStream(Boolean persistEntityBody, Boolean disableMaxRequestLength)
at System.Web.HttpRequest.GetBufferlessInputStream()
at System.Web.Http.WebHost.HttpControllerHandler.ConvertRequest(HttpContextBase httpContextBase)
at System.Web.Http.WebHost.HttpControllerHandler.BeginProcessRequest(HttpContextBase httpContextBase, AsyncCallback callback, Object state)
at System.Web.Http.WebHost.HttpControllerHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
I believe the WSFederationAuthenticationModule is attempting to read the request input stream before the IHostBufferPolicySelector can invoke the Bufferless input stream.
If I create an HttpModule and make sure it is added before the WSFAM module then I can call Request.GetBufferlessInputStream() to force it. I just need some better conditional logic. This seems like a hack.
Is there no way to get IHostBufferPolicySelector to run before the HTTP module (in this case it gets invalidated by something WSFam is doing).
public class NoBufferModule : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
void context_BeginRequest(object sender, EventArgs e)
{
var app = (sender as HttpApplication);
//TODO: Some conditional logic here.
var stream = app.Request.GetBufferlessInputStream(true);
}
}
The WSFederationAuthenticationModule will perform a Request in some places. I'm not sure there's an easy way to get around this, but have you tried setting up a location tag in your web.config, and not loading the module for POST requests to your page?
There may be other issues when you do that, but it might be worth a try. You could use DebugDiag to see if you can look at the stack of the error and see if it gives you more information about what method is calling this. I know that there is a function
"CanReadSignInResponse" that basically is checking for a session cookie on POST requests, and that needs to do a Request.Cookies. But try this with DebugDiag, and see if you can get the full stack trace:
1. Download and then install the Debug Diagnostics 1.2 (Debugdiag.msi) tool. To do this, visit the following Microsoft Web site:
2. Click Start, point to Programs, point to IIS Diagnostics, point to Debug Diagnostics Tool, and then click Debug Diagnostics Tools 1.2.
3. Usually, a popup screen asking to create a dump rule will pop up. If it doesn’t click “Add Rule”. Then click Crash, and then click Next.
4. Select “A specific IIS web Application Pool”, and click next. (If you don’t know which appPool, just select “All IIS/COM+ processes”)
5. Select the Application Pool that is failing, and click Next.
6. Under "Action type for unconfigured first chance exceptions", change to "Log Stack Trace"
7. Leave the Action Limit at 0. and click OK.
8. Click to select the Activate the rule now check box, and then click Finish.
Reproduce the error and check the log file generated, and send us the full stack if you can. Maybe if I know the exact function, we can see if someone from our WIF team has any other suggestions.
My solution was to create an HttpModule that I install in the web.config before the WSFedAuthModule. By doing this I can force the Request Input Buffer stream to be either Buffered or Bufferless. If I run install this as the first module then no other
modules (including WSFedAuthModule) can screw this up.
More on my solution:
Create a NoBufferModule that implements IHttpModule and WebHostBufferPolicySelector.
Add the module as the first modue (before WS Fam).
In the static Constructor read some config that defines which paths to flag as bufferless streams.
In IHttpModule.Init add a handler for HttpApplication.BeginRequest.
The handler for BeginRequest is important for fixing the issue I was having. Here we will force a call to Request.GetBufferlessInputStream(true) when the current request path matches our config option.
<div>
/// <summary>
/// Forces a bufferless input stream if the request path
/// is matched by the NoBufferPathRegEx setting.
/// </summary>
void context_BeginRequest(object sender, EventArgs e)
{
var app = (sender as HttpApplication);
if (IsPathNonBufferPath(app.Request.Path, app.Request.HttpMethod))
{
//This will force the app.Request to cache the current
//stream as a bufferless input stream.
var stream = app.Request.GetBufferlessInputStream(true);
}
}
</div> <div></div> <div></div> <div>Next:</div> <div></div> <div style="padding-left: 30px;">6. In the constructor replace the IHostBufferPolicySelector service (in System.Web.Http.GlobalConfiguration.Services) with the current
instance. </div> <div style="padding-left: 30px;">7. Override WebHostBufferPolicySelector.UseBufferedInputStream so that if the current request path matches the config then return false to indicate that we do not want a buffered stream. #5 & #6 would be
the same as the
solution posted here. </div> <div style="padding-left: 30px;"></div> <div style="padding-left: 30px;"></div> <div>If any one is having the same issue and wants some more detailed code, just message me and I can probably put something on github.</div>
Marked as answer by cts-mgraham on Dec 16, 2012 02:07 PM
gmetzker
Member
14 Points
6 Posts
HttpRequest.GetBufferlessInputStream or does not work when using WSFederationAuthenticationModule
Nov 16, 2012 10:56 PM|LINK
I'm having an issue and I think it's with the WSFederationAuthenticationModule. I'm using WIF along with WebAPI and I'm trying to upload large files through the web api service. I am trying to use bufferless streams for the file upload so I followed the instructions here:
The methodology for enabling bufferless streams on WebAPI is to inherit from WebHostBufferPolicySelector and return true for 'UseBufferedInputStream'. And then add this at startup:
This was working fine until I added WSFederationAuthenticationModule. When WSFederationAuthenticationModule is present in my web.config I get the exception at the bottom of this post. Is WSFam already opening the input stream and preventing HttpRequest.GetBufferlessInputStream from working?
I'm not sure if this is an issue with WSFam or HttpRequest.GetBufferlessInputStream().
Exception:
gmetzker
Member
14 Points
6 Posts
Re: HttpRequest.GetBufferlessInputStream or does not work when using WSFederationAuthenticationMo...
Nov 19, 2012 11:02 PM|LINK
I believe the WSFederationAuthenticationModule is attempting to read the request input stream before the IHostBufferPolicySelector can invoke the Bufferless input stream.
If I create an HttpModule and make sure it is added before the WSFAM module then I can call Request.GetBufferlessInputStream() to force it. I just need some better conditional logic. This seems like a hack.
Is there no way to get IHostBufferPolicySelector to run before the HTTP module (in this case it gets invalidated by something WSFam is doing).
public class NoBufferModule : IHttpModule { public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest += context_BeginRequest; } void context_BeginRequest(object sender, EventArgs e) { var app = (sender as HttpApplication); //TODO: Some conditional logic here. var stream = app.Request.GetBufferlessInputStream(true); } }cts-mgraham
Contributor
3318 Points
642 Posts
Microsoft
Re: HttpRequest.GetBufferlessInputStream or does not work when using WSFederationAuthenticationMo...
Nov 25, 2012 12:47 PM|LINK
The WSFederationAuthenticationModule will perform a Request in some places. I'm not sure there's an easy way to get around this, but have you tried setting up a location tag in your web.config, and not loading the module for POST requests to your page? There may be other issues when you do that, but it might be worth a try. You could use DebugDiag to see if you can look at the stack of the error and see if it gives you more information about what method is calling this. I know that there is a function "CanReadSignInResponse" that basically is checking for a session cookie on POST requests, and that needs to do a Request.Cookies. But try this with DebugDiag, and see if you can get the full stack trace:
1. Download and then install the Debug Diagnostics 1.2 (Debugdiag.msi) tool. To do this, visit the following Microsoft Web site:
http://www.microsoft.com/en-us/download/details.aspx?id=26798
2. Click Start, point to Programs, point to IIS Diagnostics, point to Debug Diagnostics Tool, and then click Debug Diagnostics Tools 1.2.
3. Usually, a popup screen asking to create a dump rule will pop up. If it doesn’t click “Add Rule”. Then click Crash, and then click Next.
4. Select “A specific IIS web Application Pool”, and click next. (If you don’t know which appPool, just select “All IIS/COM+ processes”)
5. Select the Application Pool that is failing, and click Next.
6. Under "Action type for unconfigured first chance exceptions", change to "Log Stack Trace"
7. Leave the Action Limit at 0. and click OK.
8. Click to select the Activate the rule now check box, and then click Finish.
Reproduce the error and check the log file generated, and send us the full stack if you can. Maybe if I know the exact function, we can see if someone from our WIF team has any other suggestions.
gmetzker
Member
14 Points
6 Posts
Re: HttpRequest.GetBufferlessInputStream or does not work when using WSFederationAuthenticationMo...
Dec 04, 2012 04:38 AM|LINK
My solution was to create an HttpModule that I install in the web.config before the WSFedAuthModule. By doing this I can force the Request Input Buffer stream to be either Buffered or Bufferless. If I run install this as the first module then no other modules (including WSFedAuthModule) can screw this up.
More on my solution:
- Create a NoBufferModule that implements IHttpModule and WebHostBufferPolicySelector.
- Add the module as the first modue (before WS Fam).
- In the static Constructor read some config that defines which paths to flag as bufferless streams.
- In IHttpModule.Init add a handler for HttpApplication.BeginRequest.
- The handler for BeginRequest is important for fixing the issue I was having. Here we will force a call to Request.GetBufferlessInputStream(true) when the current request path matches our config option.
<div>/// <summary> /// Forces a bufferless input stream if the request path /// is matched by the NoBufferPathRegEx setting. /// </summary> void context_BeginRequest(object sender, EventArgs e) { var app = (sender as HttpApplication); if (IsPathNonBufferPath(app.Request.Path, app.Request.HttpMethod)) { //This will force the app.Request to cache the current //stream as a bufferless input stream. var stream = app.Request.GetBufferlessInputStream(true); } }</div> <div></div> <div></div> <div>Next:</div> <div></div> <div style="padding-left: 30px;">6. In the constructor replace the IHostBufferPolicySelector service (in System.Web.Http.GlobalConfiguration.Services) with the current instance. </div> <div style="padding-left: 30px;">7. Override WebHostBufferPolicySelector.UseBufferedInputStream so that if the current request path matches the config then return false to indicate that we do not want a buffered stream. #5 & #6 would be the same as the solution posted here. </div> <div style="padding-left: 30px;"></div> <div style="padding-left: 30px;"></div> <div>If any one is having the same issue and wants some more detailed code, just message me and I can probably put something on github.</div>