IIS/ASP.NET receiving calls from external application to SOAP proxy server - asp.net

This is a weird one, sorry :( I have a remote server (3rd party, not under my control) that calls a defined endpoint (http://myservice.com/service.asmx), but internally before calling, it appends '.wsdl' to the URL string (so I see http://myservice.com/service.asmx.wsdl) The original server waiting for this request is expecting this, but the original server is no longer in service and I'm hoping to replace it with a 'stub'.
Basically, I'm trying to put an ASP.NET application in place to receive the requests (all currently running locally with IIS). I've used wsdl.exe to create my stub code, and it's called service.asmx. Using POSTMAN against this running service, it all works great - I can debug, see the responses etc, but if I try to rename my project to service.asmx.wsdl to accomodate for the real server making the request, I see a 405 - HTTP Verb error. I've been unable to figure out how to make this work and was thinking it's IIS handers or something like that. I've looked at IIS handers, but I can't seem to find one that would work (i.e., copying the .asmx profiles into newly created .wsdl profiles)
So my question is "Can I make the endpoint at .wsdl behave like it's an .asmx or am I approaching this all wrong?

After much hairpulling, I had to add Global.asax file to my project and implement the following method therein...
protected void Application_BeginRequest(object sender, EventArgs e)
{
var path = Request.Path;
if (path.EndsWith(".asmx.wsdl"))
Context.RewritePath(path.Replace (".asmx.wsdl", ".asmx"));
This allowed for the default asmx handlers in IIS to remain as-is and process the request from the URL by simply rewriting the URL programmatically.

Related

Disable access to a Servlet

I'm developing a WebApp using JavaEE and I use a servlet to test some stuff.
Currently, my WebApp is set as when I go to my local url localhost:8080/myApp/test , I can run my test Servlet.
My plan is to deploy my project to a Web and I want to disable the Servlet, but not delete it. I mean, if in the future I visit my remote server via URL www.myNewWeb.com/test , I would like it throws an error od do nothing.
How could I do that?
There are many possible options here:
Option 1
Remove the mapping (annotation #WebServlet or url mapping entry in web.xml). In this case, any attempt to call this servlet will end with an error generated by the JEE container of your choice. It will try to map the servlet to URL, will obviously fail and throw an exception
The obvious drawback of this method is that you need to change the deployment configuration and if you'll want to run the same artifact in another envrironment where this servlet should work you won't be able to do so.
Option 2
Create some kind of configuration, load this configuration along with your application.
In the doGet (just for the sake of example) method do something like this:
public void doGet(request, response) {
if(config.isTestServletEnabled()) { // this is where the data gets read from configuration that I've talked about before
// do your regular processing here
}
else {
// this will happen when the servlet should not be activated
// throw an exception, return HTTP error code of your choice, etc
}
}
This way doesn't have a drawback of the first method that I've explained above, however involves some code to be written.

Replacement for ASP.NET Virtual Directory for Multi-tenancy

I am working on an ASP.NET WebForms Application, using ASP.NET 4.5
The Application has multi-tenancy support. Each tenant has an own URL like:
http://myApplication.net/DemoTenant1/
Very simplified in the Login.aspx the application calls this method and translates this URL to an internal ID.
public static string getTenant(HttpRequest request)
{
return = request.Url.ToString();
}
The problem is now, we have more than 200 tenants, for each we need to define an WebApplication which is
a bunch of work :-)
probably very inefficient as an own worker process for each tenant is opend
I am looking for a smart replacement where I stay compatible to the old URLs.
I am looking for an idea how to solve this via URL Routing or maybe to mix WebForms with MVC and add a Login Controller?
Also open to other ideas...
I agree with what Alexander said, the proper way to do this would be with URL Routing.
But... If you are trying to save time...
First, remove all of your web applications;
So get rid of...
http://myApplication.net/DemoTenant1/
http://myApplication.net/DemoTenant2/
http://myApplication.net/DemoTenant3/
And then you need to make sure that typing in the following:
http://myApplication.net/
... takes you to the actual WebApplication you want to use.
Then, in the global.asax file... you need to capture 404 exceptions.
So when someone types in:
http://myApplication.net/DemoTenant1/
... it will throw a 404 exception which you could catch in your global.asax file like this:
void Application_Error(object sender, EventArgs e)
{
string urlData = Request.ServerVariables["SCRIPT_NAME"];
// do some string splitting to get the DemoTenant1 value
// Response.Redirect("~Login.aspx?tenant=DemoTenant1");
}
Its a bit messy but I have done this in the past when I was in exactly the same situation as you. Although, you do now have the routing module built by Microsoft (which I did not have at the time). I am quite sure that you can use the Routing modules within Webforms, without having to use MVC.

ASP.NET HttpModule RewritePath virtual directory cache not refreshing

I have an ASP.NET IHttpModule implementation designed to rewrite paths for serving files. The module handles only one event, PostAuthenticateRequest, as follows:
void context_PostAuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.Path.ToLower().Contains("foobar"))
{
HttpContext.Current.RewritePath("virtdir/image.png");
}
}
The path "virtdir", is a virtual directory child of the application. The application itself runs in a typical location: C:\inetpub\wwwroot\IisModuleCacheTest\ The virtual directory "virtdir" is mapped to C:\TestVirtDir\
A request to http://myserver/iismodulecachetest/foobar will, as expected, return image.png from the virtual directory. Equally, a request to http://myserver/iismodulecachetest/virtdir/image.png will return the same image file.
I then perform the following:
Request http://myserver/iismodulecachetest/foobar
Directly modify C:\testvirtdir\image.png (change its colour in paint and re-save).
Repeat.
After anywhere between 1 and 20 repeats spaced a few seconds apart, the image returned will be an out of date copy.
Once upset, the server will only return the current version after an unknown amount of time elapses (from 10 seconds up to a few minutes). If I substitute the URL in step 1 with http://myserver/iismodulecachetest/virtdir/image.png, the problem doesn't appear to arise. But strangely enough, after the problem has arisen by using the "foobar" URL, the direct URL also starts returning an out of date copy of the image.
Pertinent Details:
A recycle of the app-pool resolves the issue.
Waiting a while resolves the issue.
Repeatedly re-saving the file doesn't appear to have an effect. I'd wondered if a "file modified" event was getting lost, but once stuck I can save half a dozen modifications and Iis stil doesn't return a new copy.
Disabling cache in web.config made no difference. <caching enabled="false" enableKernelCache="false" />
The fact that this is a virtual directory seems to matter, I could not replicate the issue with image.png being part of the content of the application itself.
This is not a client-cache, it is definitely the server returning an out of date version. I have verified this by examining request headers, Ctrl+F5 refreshing, even using separate browsers.
I've replicated the issue on two machines. Win7 Pro 6.1.7601 SP1 + IIS 7.5.7600.16385 and Server 2008 R2 6.1.7601 SP1 + IIS 7.5.7600.16385.
Edit - More Details:
Disabling cache and kernel cache at the server level makes no difference.
Adding an extension to the URL makes no difference http://myserver/iismodulecachetest/foobar.png.
Attaching a debugger to IIS shows the context_PostAuthenticateRequest event handler is being triggered each time and behaving the same way whether or not the cache is stuck.
Edit2 - IIS Logs:
I enabled "Failed Request Tracing" in IIS (interesting how this works for non-failed requests also if configured appropriately. The pipeline is identical up until step 17 where the request returning the out of date version clearly shows a cache hit.
The first request looks just fine, with a cache miss:
But once it gets stuck, it repeatedly shows a cache hit:
The events after the cache hit are, understandably, quite different than the cache miss scenario. It really just looks like IIS is perfectly content to think its file cache is up to date, when it is definitely not! :(
A little further down the stack we see first request:
And then subsequent (faulty) cache-hit request:
Also note that the directory is apparently monitored, as per FileDirmoned="true".
You can do something like below.
void context_PostAuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.Path.ToLower().Contains("foobar"))
{
Random rnd = new Random();
int randomNumber = rnd.Next(int.MinValue, int.MaxValue);
HttpContext.Current.RewritePath("virtdir/image.png?"+randomNumber);
}
}
I had the same problem using the method RewritePath to address static resources in a virtual directory.
I do not have a solution for the use of this method but at the end I opted to use the method Server.TransferRequest and this shows no caching problems.
HttpContext.Current.Server.TransferRequest(newUrl);
The request transfer is processed again by the IHttpModule so you need to be careful to not produce loops.

IIS7 Application Request Routing (arr reverse proxy) combined with managed module - time out

I am trying to build a proxy that would serve requests to an internal site (hiding the origin) but at the same time inspect the packets and asynchronously post-process them.
E.g. let's say all SOAP calls to http://www.foo.com will go to http://192.168.1.1, and at the same time be stored in a DB for post analysis. The internal server is a black box, so changing something on it is out of this question scope.
Anyway, I have configured ARR, with reverse proxy, made URL rewrite filter with wildcards, all works flawless. Then, I tried to add an managed HttpModule written in C#, and hooked to Application_BeginRequest and Application_EndRequest. I am able to access request headers, response headers on end request (app pool being in integrated mode) and even able to read response content from the outputstream by setting a filter on Response.Filter, that caches all writes in an additional memory stream.
The problem is that the moment I try to read (inside the module BeginRequest handler) the input stream from the request, ARR stays a while and throws a
HTTP Error 502.3 - Bad Gateway The
operation timed out Handler
ApplicationRequestRoutingHandler
Error Code 0x80072ee2
So it times out.
Looking with Failed Request Tracing I see:
MODULE_SET_RESPONSE_ERROR_STATUS
Warning
ModuleName="ApplicationRequestRouting",
Notification="EXECUTE_REQUEST_HANDLER",
HttpStatus="502", HttpReason="Bad
Gateway", HttpSubStatus="3",
ErrorCode="2147954402",
ConfigExceptionInfo=""
SET_RESPONSE_ERROR_DESCRIPTION Warning
ErrorDescription="The operation timed
out"
Now any similar posts on the net didn't helped as this isn't a timeout error (proxy has 120 seconds setting, page answers in under 100 ms), and the moment I comment the code of the handler that tries to read FORM data or InputStream data, everything works as a charm.
Even if I set the position of the inputstream to 0 after reading it, I still get timeouts.
If I read the input stream on EndRequest, it gets 0 bytes, even if it was a POST request. (which is clearly wrong)
Does ARR has a bug in the fact that I try to read an input stream before it tries to re-route it?
Things used: Windows Server 2008 R2
IIS 7.5 ARR v2 .Net Framework 3.5
module
Ideas?
Thanks
/Cosmin
If you can switch to .Net Framework 4, there is a solution for this.
After you are done with your BeginRequest/EndRequest in your HttpModule event handler, add a call to HttpRequest.InsertEntityBody.
/* BeginRequest event: Executes before request is processed */
private void Application_BeginRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpRequest request = application.Context.Request;
// Do something with request
DoMyOwnRequestProcessing(request);
// After you finish, make sure IIS gets the entity body
// For example, Application Request Routing needs this
request.InsertEntityBody();
}
Take a look at this on MSDN: HttpRequest.InsertEntityBody.
I know this is a year old question, but I just went through the same thing and found a solution. So, I'm posting it here for anyone else that runs into this.
In my case I only saw the timeout issue with POST requests.
It appears that the 2.0/2.1 ARR assumes that the input stream will be at the start of the posted data. However, the following code (for example) will break this assumption:
HttpContext context = HttpContext.Current;
HttpRequest request = context.Request;
string value = request.Params["Name"];
The key is how Params is described
Gets a combined collection of System.Web.HttpRequest.QueryString,
System.Web.HttpRequest.Form, System.Web.HttpRequest.ServerVariables,
and System.Web.HttpRequest.Cookies items."`
When the request is a POST, accessing Params will read the posted data from the input stream, invalidating ARR's assumption. As will reading from the input stream.
I knew the data I needed was in the query string, not the posted data, so I worked around this by accessing the QueryString instead of Params. This avoids reading the posted data and works fine for me.
string value = request.QueryString["Name"];
This issue appears to be fixed in ARR 2.5.
Upgrading ARR appears to be the only solution if you need to access posted data before handing off to ARR. The key is to let HttpRequest handle acquiring the data into Params. If you read it directly it will not work.
I just ran into this bug and your experiences helped me determine the root cause.
My main server is MVC based and it looks at the Request.Form values in the Application_BeginRequest method. If the form values are accessed ARR fails to forward the body of a HTTP POST request. GET requests will work fine since there is no body.
I have routes.IgnoreRoute ("Forum/{*pathInfo}"); as a registered route but ARR runs as a HttpModule and doesn't kick-in until later in the pipeline. That means my MVC based application is given the opportunity to access the content of the POST body which somehow prevents ARR from accessing the body itself and forwarding it to the proxy'd server.
Here is Cosmin's related post on the iis.net forums: ARR 2.0 BUG - combined with managed http module timeout on read inputstream
In my application I have all myserver.com/Forum/* requests being reverse proxy'd to a separate application on another server. So I simply checked the HttpContext.Current.Request.Url in my MVC application's Application_BeginRequest method to make sure it does not contain /Forum before accessing the Request.Form values. Once I did that the POST bodies made it through ARR just fine.
UPDATE: after further testing it appears that there are still problems with ARR as POST from non-authenticated users still fails. Instead of the main website being MVC I created a dummy IIS .NET 4.0 website with a single Default.html document. But I still ran into problems with POST requests and ARR. Then I switch the application pool to ASP.NET 2.0 and what do you know, it works. At this point I have to assume that something in the .NET 4.0 pipeline is accessing the input stream which prevents ARR from accessing the input stream itself in order to forward the POST body.
按照正常来说,再iis网站界面会有一个application request
routing cache 的 icon, 可以点击 设置timeout 但是这里没有显示
找到了 官方说明可以用命令行解决这个问题
https://blogs.iis.net/richma/502-3-bad-gateway-the-operation-timed-out-with-iis-application-request-routing-arr
​
blogs.iis.net
执行以下命令,然后重启下网站服务
进入到C:\Windows\System32\inetsrv 打开管理员命令行工具执行以下命令
appcmd.exe set config -section:system.webServer/proxy /timeout:"00:00:45" /commit:apphost
重启下网站服务
我写的原文地址
https://zhuanlan.zhihu.com/p/157557980

How do I get the host domain name in ASP .NET without using HttpContext.Current.Request?

I've got an ASP .Net application running on IIS7. I'm using the current url that the site is running under to set some static properties on a class in my application. To do this, I'm getting the domain name using this (insde the class's static constructor):
var host = HttpContext.Current.Request.Url.Host;
And it works fine on my dev machine (windows XP / Cassini). However, when I deploy to IIS7, I get an exception: "Request is not available in this context".
I'm guessing this is because I'm using this code in the static constructor of an object, which is getting executed in IIS before any requests come in; and Cassini doesn't trigger the static constructor until a request happens. Now, I didn't originally like the idea of pulling the domain name from the Request for this very reason, but it was the only place I found it =)
So, does anyone know of another place that I can get the host domain name? I'm assuming that ASP .Net has got to be aware of it at some level independent of HttpRequests, I just don't know how to access it.
The reason that the domain is in the request is...that's what's being asked for. For example these are a few stackexchange sites from http://www.stackexchangesites.com/:
http://community.ecoanswers.com
http://www.appqanda.com
http://www.irosetta.com/
If you ping them, you'll see they all point to the same IP/Web Server and be served by the same app (or multiple apps in this case, but the example holds if it was one big one)...but the application doesn't know which one until a host header comes in with the request asking the server for that site. Each request may be to a different domain...so the application doesn't know it.
If however it doesn't change, you could store it as an appSetting in the web.config.
Use global.asax or write a HttpModule and subscribe to start request events. You will have the request passed into your event handler.
Use this instead:
HttpRuntime.AppDomainAppVirtualPath
Or if you want the physical path:
HttpRuntime.AppDomainAppPath
For further reading:
http://weblogs.asp.net/reganschroder/archive/2008/07/25/iis7-integrated-mode-request-is-not-available-in-this-context-exception-in-application-start.aspx

Resources