Custom js httphandler in visual studio 2013 - c#

I'm trying wire up a custom IHttpHandler to process request to my website for *.js files. For the life of me I can't get my httphandler to even be created by IISExpress when a request is made for a js file to my web server. I've tried several variations of the system.webServer handlers setting including.
<add name="MyHandler"
type="BusinessLayer.Web_Stuff.MyHandler, BusinessLayer"
verb="*"
path="*.js"
resourceType="Unspecified"
preCondition="integratedMode"
modules="IsapiModule"
scriptProcessor="c:\windows\Microsoft.net\framework\v4.0.30319\aspnet_isapi.dll"/>
and
<add name="JSHandler"
type="BusinessLayer.Web_Stuff.MyHandler, BusinessLayer"
verb="GET,POST" path="*.js"
resourceType="Unspecified"
preCondition="integratedMode" />
I am running this in Visual Studio 2013 using IISExpress. If i change the path to *.test instead of js then this handler works without any problems, but i cant make it work for *.js files. It seems like IISExpress is handling those requests itself by just serving the files off of disk. Does anyone know how to bypass that so i can make my handler process requests for js files.
Correction: When i use the top web.config setting with IsapiModule specified, an instance of MyHandler is instantiated however the ProcessRequest(HttpContext context) method of the interface is never called on my object. With the bottom definition, no instances of my handler are ever instantiated.

After fighting with this for several hours i finally found the answer. The key was I had to add an attribute to the modules xml element in system.webServer
<modules runAllManagedModulesForAllRequests="true" >
Without this attribute, the process request handler was not being called. After setting that, this is all that was need in the handlers section.
<add name="JSHandler"
type="BusinessLayer.Web_Stuff.ScriptMinifyHandler, BusinessLayer"
verb="*"
path="*.js"
resourceType="Unspecified"
preCondition="integratedMode" />
I will have to read a bit more about this setting, but if anyone can tell me more about why that works I'd love to hear it.

Related

ASP.NET Core + Framework in IIS getting HTTP 404

Ok - this is my first deployment of an ASP.NET Core app. One wrinkle to keep in mind is that I am using ASP.NET Core 2.2 and targeting Framework version 4.6.2 (not .Net Core). It all runs fine on my local machine with VS2017 and IISExpress.
I went through the procedure outlined by MS here: Host ASP.NET Core on Windows with IIS The documentation is long and complicated, but I think I covered everything. It makes one thing clear: The in-process hosting model isn't supported for ASP.NET Core apps that target the .NET Framework. So, I know I need to use Out-of-Proc.
Some other points:
I published the app to a local folder and copied it to the server without any changes.
I created the new app in the Default Web Site and gave it its own app pool - set as "No Managed Code"
Out-of-proc is the default, so I have not done any special config for this.
I have confirmed that AspNetCoreModuleV2 appears in the list of Modules.
The Result
Every page I hit I get HTTP404. I am running IE locally on the server and using a URL like: http://localhost/MyApp/Home/MyView
The application pool shows having 1 application running.
The App Event Log shows a message like: Application '/LM/W3SVC/2/ROOT/MyApp' started process '8864' successfully and process '8864' is listening on port '37706'. It shows no errors.
I have tried adding a default.htm file to the root of the app and loading the static page directly (using http://localhost/MyApp/default.htm). This gives 404. If I remove the web.config, this page will load.
I really didn't expect deploying the app to be this complicated.
Can anyone provide any guidance on how to troubleshoot or fix this problem?
Update 1: Web.config is below. I have tried with and without hostModel=... aspNetCore logs show successful startup. Nothing is added to the log with each page access attempt (seems weird)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
-->
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
<remove name="BlockViewHandler" />
<add name="JavaScript" path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler" />
<add name="CSS" path="*.css" verb="GET,HEAD" type="System.Web.StaticFileHandler" />
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
<aspNetCore processPath=".\My.App.Name.exe" arguments="" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="OutOfProcess">
<environmentVariables />
<handlerSettings>
<handlerSetting name="debugLevel" value="file" />
<handlerSetting name="debugFile" value="d:\Log\MyApp.log" />
</handlerSettings>
</aspNetCore>
</system.webServer>
</configuration>
<!--ProjectGuid: ee76911e-decb-48b7-bd74-36ebfbdb22b6-->
Solved! I was making use of the ASPNETCORE_ENVIRONMENT environment variable, but was unaware that the publish process does not put this in web.config. I added this to Web.config:
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
and the pages now load.
The most useful diagnostics I found were at this link Troubleshoot ASP.NET Core on IIS There they recommended that I run My.App.Name.exe from the command prompt. This creates a web process and assigns it to a port and gives you all the console output. This allowed me to figure out it was actually half working and that led me to the fact that I was missing the Env Variable.
Thanks again for the suggestions...

Include Scripts from Feature folder in ScriptBundle

I'm trying to include js files that are not part of the original ~/Scripts folder included in a MVC web project. Rather I have my script files inside of my Feature folder like: ~/Features/MyNewFeature/Scripts
However when running the app I get nothing but 404 errors when the request goes to find those js files. I'm not sure what I'm missing or if there's something that needs to be added to make this work. I know I've read that js files have to be in the Scripts folder but I'm having a hard time believing that since there's a way around not having your cshtml files inside a /Views folder.
bundles.Add(new ScriptBundle("~/bundles/mynewfeature")
.Include("~/Features/MyNewFeature/Scripts/Settings.js"));
Then to render in cshtml:
#Scripts.Render("~/bundles/mynewfeature")
So the problem was first starting once the/Views Web.config got moved to the Features folder. To fix the problem I was able to add a new handler that explicitly allows js files.
<system.webServer>
<handlers>
<remove name="BlockViewHandler" />
<add name="JavaScript" path="*.js" verb="GET, HEAD" type="System.Web.StaticFileHandler" />
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>

Make IIS 7.5 pass *.xml requests to asp.net

How do I configure IIS 7.5 to forward all *.xml file requests to asp.net engines so i can handle them in Global.asax and rewrite the path to a *.aspx file? Now IIS is expecting to find them directly on disk. I will use this do dynamically generate my sitemap.xml
You can force static files to go through the ASP.NET pipeline by editing your web.config:
<system.webServer>
<handlers>
<add name="XMLHandler" type="System.Web.StaticFileHandler" path="*.xml" verb="GET" />
</handlers>
</system.webServer>
HTTP Handlers and HTTP Modules Overview
How to: Register HTTP Handlers

Custom server control and Generic Web handler

I'm creating a custom server control which uploads files asynchronously to the server.
This solution uses flash element that posts the files to Generic Web handler aka ashx which then saves the posted file in a desired location.
It works grate, but with this approach I do need to create ashx file in each project, potentially, to handle the posts from the flash element.
What I would like to achieve is fully encapsulated server control that will use it's own ashx (or whatever can replace it) handler to upload the files.
Is it possible to do? Any ideas would be welcome.
Thanks.
You could include the handler within the class library containing the control and then only register it in web.config using the <httpHandlers> section:
<configuration>
<system.web>
<httpHandlers>
<add verb="*"
path="upload.ashx"
type="MyControl.MyUploadHandler.New, MyControl" />
</httpHandlers>
<system.web>
</configuration>
and if you are using IIS 7 Integrated pipeline mode to the <handlers> section:
<system.webServer>
<handlers>
<add name="UploadHandler"
verb="*"
path="upload.ashx"
type="MyControl.MyUploadHandler.New, MyControl" />
</handlers>
</system.webServer>
And if you are using ASP.NET 4.0 you could checkout the PreApplicationStartMethod infrastructure which allows you to dynamically register handlers:
[assembly: WebActivator.PreApplicationStartMethod(typeof(MyControl.StartUp), "PreApplicationStart")]

IIS7 file mappings - .asax, .ashx, .asap

IIS enables us to also configure Asp.Net file mappings. Thus besides aspx, IIS also invokes Asp.Net runtime, when requests have the following file extensions:
a) .ascx --> .asmx extension is used to request user controls.
Since user controls can’t be accessed directly, how and why would anyone send a request to a user control?
b) .ashx --> this extension is used for HTTP handlers.
• But why would you want to request an .ashx page directly instead of registering this handler inside configuration file and enable it to be called when files with certain ( non ashx ) extensions are requested?
• Besides, since there can be several Http handlers registered, how will Asp.Net know which handler to invoke if they all use ashx extension?
• What does the requested ashx file contain? Perhaps a definition of a Http handler class?
• I know how we register Http handlers to be invoked when non-ashx pages are requested, but how do we register Http handler for ashx page?
c) .asax --> This extension is used to request a global application file
• Why would we ever want to call Global.asax directly?
• I assume that when request is made for Global.asax, an object derived from HTtpApplication class is created, except this time no web page processing takes place?
thanx
Q - Besides Asp.Net being able to request global.asax for compilation, is there any other reason why I would choose to request file with .asax extension directly?
• ashx files don't have to be registered. They are basically a simpler aspx, for when you don't need the entire page life cycle. A common use is for retrieving dynamic images from a database.
So if I write a Http handler, I should put it in a file with .ashx extension and Asp.Net will build an HttpHandler object similarly to how it builds a page instance from .aspx file?
• If a hacker did try to make a request for one of these files, what would you want to happen? You certainly wouldn't want IIS to treat it like a text file and send the source for your app down to the browser.
Asp.Net could do the same it does with .cs, .csproj, .config, .resx, .licx, .webinfo file types. Namely, it registers these file types with IIS so that it can explicitly prevent users from accessing these files
•Just because you don't expect requests from the browser for a resource, it doesn't mean you don't want that resource handled by the asp.net engine. These extensions are also how ASP.Net picks up files to compile for the web site model sites.
But then why doesn’t Asp.Net also allow .cs, .csproj, .config, .resx, .licx, .webinfo files to be directly requested?
a) and c) - as far as I am aware, these are not exposed to process any external requests
my book claims the two are mapped in IIS
I appreciate your help
EDIT:
b) The .ashx extention is defined in a config file it's just not the web.config, its in the machine.config
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
http://msdn.microsoft.com/en-us/library/bya7fh0a.aspx
Why use .ashx: The difference is that the .NET class that handles a .ashx reads the Page directive in the .ashx file to map the request to a class specified in that directive. This saves you from having to put an explicit path in the web.config for every handler that you have, which could result in a very long web.config.
I thought Http handler class was defined inside .ashx file, but instead file with .ashx extension only contains Page directive?
Since I’m not 100% sure if I understand this correctly: Say we have ten Http handlers we want to invoke by making a request to IIS7. I assume for each Http handler there will be specific .ashx file --> thus if request is made for FirstHandler.asxh, then handler specified inside that file will be invoked?
YET ANOTHER EDIT:
I must confess that I’m still a bit unsure about ashx extension.
I realize that by using it we can for example create 'hey.ashx' page, where Page directive will tell which class ( Http handler) to invoke when request is made for 'hey.ashx' – thus no need to register Http handler in web.config.
But if you use Http handlers that way, then they will only get invoked when requests are made for files with .ashx extension. Thus, if I want Http handler to be invoked for files with other extensions, such as .sourceC, then I will still need to register Http handler in web.config?!
A few points:
asmx files are not the same as ascx files. You use them for web services (soap) rather than web controls.
ashx files don't have to be registered. They are basically a simpler aspx, for when you don't need the entire page life cycle. A common use is for retrieving dynamic images from a database.
If a hacker did try to make a request for one of these files, what would you want to happen? You certainly wouldn't want IIS to treat it like a text file and send the source for your app down to the browser.
Just because you don't expect requests from the browser for a resource, it doesn't mean you don't want that resource handled by the asp.net engine. These extensions are also how ASP.Net picks up files to compile for the web site model sites.
a) and c) - as far as I am aware, these are not exposed to process any external requests
b) by default, it will look for a .ashx file with the path/name requested. This makes it really easy to add a handler to a web site, with no configuration necessary.
Update: In a you also mentioned asmx. My take is the book is explaining some ajax related feature, with some comments regarding:
Asp.net doesn't allow making requests pointed to .ascx.
You can make a request to a web service (.asmx) to get you the info.
There are some built in features to help you with the above.
To definitely clear any confusion you might have on what asp.net does with these requests, check the web.config in:
%systemroot%\Microsoft.NET\Framework\v2.0.50727\CONFIG
As you can see (posted mine below), asp.net excludes pretty much any of the files that you are unsure if they were receiving special treatment. Notice there is *.cs, *.acsx, *.asax.
<add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.browser" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sitemap" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.dll.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
<add path="*.exe.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="True"/>
<add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.csproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vbproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.webinfo" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.licx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.resx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.resources" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.mdb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vjsproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.java" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.jsl" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldb" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ad" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.dd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cd" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.adprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.lddprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sdm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.sdmDocument" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.mdf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.ldf" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.exclude" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.refresh" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
Also, bear in mind that IIS might not be configured to map some requests (MIME types) to the ASP.NET pipeline.
a) .ascx can't be accessed directly becasue the default handler is the class System.Web.HttpForbiddenHandler
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
.asmx files can be called directly, they are webmethods (though you usually have to make POST request, unless you specify to allow GET's in the web.config
b) The .ashx extention is defined in a config file it's just not the web.config, its in the machine.config
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
http://msdn.microsoft.com/en-us/library/bya7fh0a.aspx
Why use .ashx: The difference is that the .NET class that handles a .ashx reads the Page directive in the .ashx file to map the request to a class specified in that directive. This saves you from having to put an explicit path in the web.config for every handler that you have, which could result in a very long web.config.
--
c) Global.asax: i don't use gloabl.asax, i rather use the very elegant HttpModule solution, but it's probably setup for legacy sites that had global.asax files.

Categories