I am trying to build a webservice that manipulates http requests POST and GET.
Here is a sample:
public class CodebookHttpHandler: IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod == "POST")
{
//DoHttpPostLogic();
}
else if (context.Request.HttpMethod == "GET")
{
//DoHttpGetLogic();
}
}
...
public void DoHttpPostLogic()
{
...
}
public void DoHttpGetLogic()
{
...
}
I need to deploy this but I am struggling how to start. Most online references show making a website, but really, all I want to do is respond when an HttpPost is sent. I don't know what to put in the website, just want that code to run.
Edit:
I am following this site as its exactly what I'm trying to do.
I have the website set up, I have the code for the handler in a .cs file, i have edited the web.config to add the handler for the file extension I need. Now I am at the step 3 where you tell IIS about this extension and map it to ASP.NET. Also I am using IIS 7 so interface is slightly different than the screenshots. This is the problem I have:
1) Go to website
2) Go to handler mappings
3) Go Add Script Map
4) request path - put the extension I want to handle
5) Executable- it seems i am told to set aspnet_isapi.dll here. Maybe this is incorrect?
6) Give name
7) Hit OK button:
Add Script Map
Do you want to allow this ISAPI extension? Click "Yes" to add the extension with an "Allowed" entry to the ISAPI and CGI Restrictions list or to update an existing extension entry to "Allowed" in the ISAPI and CGI Restrictions list.
Yes No Cancel
8) Hit Yes
Add Script Map
The specified module required by this handler is not in the modules list. If you are adding a script map handler mapping, the IsapiModule or the CgiModule must be in the modules list.
OK
edit 2: Have just figured out that that managed handler had something to do with handlers witten in managed code, script map was to help configuring an executable and module mapping to work with http Modules. So I should be using option 1 - Add Managed Handler.
I know what my request path is for the file extension... and I know name (can call it whatever I like), so it must be the Type field I am struggling with. In the applications folder (in IIS) so far I just have the MyHandler.cs and web.config (Of course also a file with the extension I am trying to create the handler for!)
edit3: progress
So now I have the code and the web.config set up I test to see If I can browse to the filename.CustomExtension file:
HTTP Error 404.3 - Not Found
The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.
So in IIS7 I go to Handler Mappings and add it in. See this MSDN example, it is exactly what I am trying to follow
The class looks like this:
using System.Web;
namespace HandlerAttempt2
{
public class MyHandler : IHttpHandler
{
public MyHandler()
{
//TODO: Add constructor logic here
}
public void ProcessRequest(HttpContext context)
{
var objResponse = context.Response;
objResponse.Write("<html><body><h1>It just worked");
objResponse.Write("</body></html>");
}
public bool IsReusable
{
get
{
return true;
}
}
}
}
I add the Handler in as follows:
Request path: *.whatever
Type: MyHandler (class name - this appears correct as per example!)
Name: whatever
Try to browse to the custom file again (this is in app pool as Integrated):
HTTP Error 500.21 - Internal Server Error
Handler "whatever" has a bad module "ManagedPipelineHandler" in its module list
Try to browse to the custom file again (this is in app pool as CLASSIC):
HTTP Error 404.17 - Not Found
The requested content appears to be script and will not be served by the static file handler.
Direct Questions
1) Does the website need to be in CLASSIC or INTEGRATED mode? I don't find any reference of this in the online material, whether it should be either.
2) Do I have to compile the MyHandler.cs to a .dll, or can I just leave it as .cs? Does it need to be in a bin folder, or just anywhere in root?
RE your questions:
I don't know the answer to the first one (CLASSIC or INTEGRATED); but I can help with the second...
Yes you'll need to compile it first. I have never tried deploying dll's to anywhere other than the bin, given that that's the standard I would be suspect in putting them anywhere else even if it did work.
The way I deploy HttpHandlers is quiet straight forward - all the hard work's done in web.config, I'v enever had to go into IIS to change any settings.
For a start, for the http request to be handled by ASP.NET you need to use a request suffix that's already piped to ASP.NET - like .aspx or ashx. If you want to use something else you will need to config IIS to do this, as per your managed handler img above.
I tend to use .ashx e.g: http://localhost/foo/my/httphandler/does/this.ashx
All you need to do (assuming you've compiled athe HttpHandler into a DLL and deployed it to the site) is add the necessary config.
<configuration>
<system.web>
<httpHandlers>
<add verb="*"
path="*.ashx"
type="MyApp.PublishingSystem.HttpHandlers.GroovyHandler, MyApp.PublishingSystem" />
</httpHandlers>
</system.web>
</configuration>
Obviously (?) you can change / restrict the scope using the path, e.g:
path="*.ashx"
path="*ListWidgets.ashx"
path="*Admin/ListWidgets.ashx"
More info here: http://msdn.microsoft.com/en-us/library/ms820032.aspx
An important gotcha to look out for is the order in which you declare your HttpHandlers in the config; from what I remember ones declared first take precedent. So in this example...
<add verb="*" path="*foo.ashx" type="MyApp.PublishingSystem.HttpHandlers.FooHandler, MyApp.PublishingSystem" />
<add verb="*" path="*.ashx" type="MyApp.PublishingSystem.HttpHandlers.GroovyHandler, MyApp.PublishingSystem" />
...the groovy handler will handle all HttpRequests except any that end in foo.ashx
By the way, I make use of HttpHanldrs in my open source .net CMS / app framework, you might find some helpful code there (?): http://morphfolia.codeplex.com/
Make sure the app pool's .NET Framework Version is set correctly...
I deployed a .NET 4.0 web app on a .NET 2.0 app pool and got this error. Set the app pool to v4.X and the ashx was served like a champ.
Related
In my ASP.NET MVC website, I have code in the RouteConfig.cs file to force the URL to include "www":
using Canonicalize;
using System.Configuration;
using System.Web.Routing;
namespace MyWebsite
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
if (ConfigurationManager.AppSettings["Production"] == "true")
{
routes.Canonicalize().Www();
}
}
}
}
I host my website in Azure, which has "deployment slots." I push my code out to a "staging" slot, test, and then "swap" the "staging" slot with the "production" slot.
In the code above, you can see I'm conditionally including routes.Canonicalize().Www(); only for the production slot. This is because the staging slot uses a URL that doesn't allow "www."
The problem is that it seems like the code in the RouteConfig.cs file is only fired on the initial website load. When I load the website, RouteConfig.cs is executed, and routes.Canonicalize().Www(); is correctly excluded. When I swap the slots, the RouteConfig.cs code does not appear to be re-executed, and routes.Canonicalize().Www(); remains excluded, which is not what I want.
Is there a way I can reliably and accurately have routes.Canonicalize().Www(); included only for the production slot?
I would suggest you to use application initialization module in this scenario where you can call you function to add routes.Canonicalize().Www().
The application initialization module has been implemented and is available to use while you swap content between deployment slots. This module has also been implemented regarding all other operations in which a new worker is provisioned (such as auto scale, manual scale or Azure fabric maintenance). Namely, you can proactively perform initialization tasks before your app becomes available.
In order to enable the said module you need to create an applicationInitialization section where you shall define the url to be hit for the initialization task to begin. You have also the option to specify the hostName to be used for the warm up requests, something that may prove really helpful for debugging and monitoring purposes. If not otherwise specified, the “localhost” will be used as host name.
<system.webServer>
<applicationInitialization>
<add initializationPage="/app/initialize" hostName="warmup-requests.domain.com"/>
</applicationInitialization>
<system.webServer>
Following the above, the swap operation between deployment slots will be completed after the code under “app/initialize” url is executed.
Reference:
https://ruslany.net/2015/09/how-to-warm-up-azure-web-app-during-deployment-slots-swap/
https://feedback.azure.com/forums/169385-web-apps/suggestions/6972595-application-initialization-to-warm-up-specific-pag
Hope it helps.
I have created a WPF application (contains 8 projects).
one project is of type (Class Library) ,this dll contains class which implement
System.Web.IHttpHandler as the following.
public class ReportFileHttpHandler : IHttpHandler
{
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
// some code
}
}
this HttpHandler is designed to interrupt the IIS request and handle the requrest of the xml file.
I also created a web.config file which exists inside this dll.
<system.webServer>
<handlers>
<add verb="*" path="*.xml" type="ReportFileHttpHandler" name="ReportFileHttpHandler"/>
</handlers>
Every thing is good here.
I want to do the following : I want to test the code inside the "ReportFileHttpHandler" ,so I need to host the my WPF application within (inside) the IIS to make test.
in this way I can write URL inside the Browser (which end with .xml) to execute the code in the method
public void ProcessRequrest(HttpContext context)
How can I Host the WPF application inside the IIS ?
any idea will be helpful, thank you
Create a webapplication in IIS say MyWPFApp.
Set physical path of application to directory where ReportFileHttpHandler assembly resides say C:\xxx\ReportFileHttpHandler\bin\Debug.
Make sure that ReportFileHttpHandler.dll and web.config are in same directory.
Browse url http://localhost/mywpfapp/myfile.xml in browser.
If you attach w3wp.exe process corresponding to app pool of your web application in Visual Studio, you should be able to debug your handler dll.
Very simple question, but nonetheless confusing. According to the Microsoft documentation, it is necessary to register a HttpHandler (used to serve images dynamically from DB) in the <handlers> section of the Web.Config file:
How to: Register HTTP Handlers
This was also specified in a previous answer on this topic:
HttpHandler not Working in IIS 7
The confusion stems from the fact that I currently have it working in an ASP.NET Web Forms project without any entry in the config file. Can someone shed some light on this and if it may effect the performance of the handler for this particular task?
public class ImageHandler : IHttpHandler
{
....
}
It wasn't entirely clear in your question, but in the comments we have established that you are asking why a handler that's exposed via an ASP.NET .ashx file does not need to be mapped. The answer is simple: when ASP.NET is installed it adds a global handler to IIS7 for the *.ashx extension with the name SimplerHandlerFactory-Integrated and SimpleHandlerFactory-Integrated-4.0. This handler simply acts like a wrapper and executes the underlying IHttpHandler implementation that is pointed to by the ASHX.
We have a web application where we are using global.asax for url rewriting. We use a compiled version of the site on the live server.
As a part of modification request, we had to add some custom native AJAX code where javascript would call a webservice to update the content of the page. For being able to call the webservice with extension .asmx, we modified the url rewriting code to handle asmx requests seperately.
this arrangement works fine on the local machine, but when we publish the site and deploy it on the live server, the new code doesnt seem to get included. It still skips the condition to check the ".asmx" extension, and throws a page not found exception considering the webservice name as a page name.
We have tried looking all over and googled for such things as well.. but no avail..
any pointers on what might be going wrong.. ?
Assuming your URL rewriting is good (isn't that normally implemented as a HttpModule?) I'd check to make sure that there's an ISAPI mapping in IIS on production that sends .asmx requests to ASP.NET.
If you think your changes to the global.asax haven't been rejitted then you can always stop the application pool, go find your web applications compiled bits in c:\windows\microsoft.net\framework[version]\temporary asp.net files... and delete the jitted version. I've seen ASP.NET miss when it comes to Jitting changes before.
I'd also consider running http fiddler (IE) or tamper data (FireFox extension) on one of the pages that makes calls to the web service. It will tell you exactly how the page is calling the web service and you can validate that the called URL is correct.
There is machine.config file where you can add HttpModules. I also think that you can do that through web.config.
One reason I can think of is that in the Web.config, you might have configured the routing module in the system.web section but not in system.webServer (or at least forgot something in there).
I the similar problem before and the solution was to remove the module & add it again in the system.webServer section of the Web.config like this:
<system.webServer>
<modules>
<remove name="UrlRoutingModule" />
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, e="RoleManager" type="System.Web.Security.RoleManagerModule"/>
</modules>
</system.webServer>
It might be a different module or handler but the idea is basically the same. It's important to "remove" the module first.
I am using Context.RewritePath() in ASP.NET 3.5 application running on IIS7.
I am doing it in application BeginRequest event and everything works file.
Requests for /sports are correctly rewritten to default.aspx?id=1, and so on.
The problem is that in my IIS log I see GET requests for /Default.aspx?id=1 and not for /sports.
This kind of code worked perfectly under IIS6.
Using Microsoft Rewrite module is not an option, due to some business logic which has to be implemented.
Thanks.
EDIT:
It seems my handler is too early in the pipeline, but if I move the logic to a later event, than the whole rewrite thing doesn't work (it's too late, StaticFileHandler picks up my request).
I googled and googled, asked around, can't believe that nobody has this problem?
EDIT:
Yikes! Here's what I found on the IIS forum:
"This is because in integrated mode, IIS and asp.net share a common pipeline and the RewritePath is now seen by IIS, while in IIS6, it was not even seen by IIS - you can workaround this by using classic mode which would behave like IIS6."
Final update: Please take a look at my answer below, I've updated it with results after more than a year in production environment.
After some research, I've finally found a solution to the problem.
I have replaced the calls to Context.RewritePath() method with the new (introduced in ASP.NET 3.5) Context.Server.TransferRequest() method.
It seems obvious now, but not event Senior Dev Engineer on IIS Core team thought of that.
I've tested it for session, authentication, postback, querystring, ... issues and found none.
Tommorow I'll deploy the change to a very hight traffic site, and we'll soon know how it actually works. :)
I'll be back with the update.
The update: the solution is still not entirely on my production servers but it's tested and it does work and as far as I can tell so far, it's a solution to my problem. If I discover anything else in production, I will post an update.
The final update: I have this solution in production for over a year and it has proven to be a good and stable solution without any problems.
You could set the path back to the original value after the request has been processed but before the IIS logging module writes the log entry.
For example, this module rewrites the path on BeginRequest and then sets it back to the original value on EndRequest. When this module is used the original path appears in the IIS log file:
public class RewriteModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += OnBeginRequest;
context.EndRequest += OnEndRequest;
}
static void OnBeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
app.Context.Items["OriginalPath"] = app.Context.Request.Path;
app.Context.RewritePath("Default.aspx?id=1");
}
static void OnEndRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
var originalPath = app.Context.Items["OriginalPath"] as string;
if (originalPath != null)
{
app.Context.RewritePath(originalPath);
}
}
public void Dispose()
{
}
}
I've had exactly the same problem. One way around this is to use Server.Transfer instead of Context.RewritePath. Server.Transfer doesn't restart the entire page lifecycle so the original URL will still be logged. Be sure to pass "true" for the "preserveForm" parameter so that the QueryString and Form collections are available to the 2nd page.
Old question, but I found I did not encounter your problem when I did the following:
a) A rewrite rule in web.config to direct all requests to /default.aspx, eg:
<rule name="all" patternSyntax="Wildcard" stopProcessing="true">
<match url="*"/>
<action type="Rewrite" url="/default.aspx"/>
</rule>
b) Called RewritePath in the Page_PreInit event of default.aspx, to rewrite the URL and querystring as what was passed in the request (ie. the location that doesn't exist).
For example, I request "/somepage/?x=y" (which doesn't exist).
a) Web.config rule maps it to /default.aspx
b) Page_PreInit rewrites it back to "/somepage/?x=y".
The result of this, in IIS 7 (Express and production) is that the server log reflects "/somepage" for stub and "x=y" for query, and all the Request object properties reflect the requested (non-existent) URL (which is what I wanted).
The only weird effect is, in IIS Express, the log item is written twice. However this doesn't happen in production (Windows Server 2008 R2).