BUG: IIS7 managed requests - configuration

(I don't know whether should I also post this question to ServerFault, since it's about IIS configuration?)
In IIS7 we can tell a module to run for managed content (thus speeding up static content serving) by:
<modules>
...
<add name="WhateverName"
type="WhateverType"
preCondition="managedHandler"
...
</modules>
But. This works fine and dandy as long as there's also a file name (with extension) in the requested URL. If it's omitted it IIS7 will think you want static content and managed modules won't run.
http://localhost/ <-- this one will skip managed handlers
http://localhost/default.aspx <-- this one will run them
If I manually set IIS7 default document, so the first one is default.aspx, I can see no difference there's no difference. To me this looks, walks and sounds like a bug. And it is a bug! Why? Because when I request for the first one, it is a managed request, isn't it. Of course it is. But IIS7 treats it as a static request. So? It's a bug. This request should be treated as managed.
How can I convince IIS7 to run managed handlers for URL requests without file names inside?
Help with thinking
Let me help you a bit with thinking: If I'd reorder system.webServer/handlers, I'm sure could solve this. Before the last StaticFile handler that points to StaticFileModule, DefaultDocumentModule and DirectoryBrowsingModule I should be running integrated asp.net handler on Directory requests. Or write my own handler, that would append default document to any directory request. I'm pretty sure one of these should solve it. But how would I have to configure/develop it?

The problem is in request-processing order. IIS7 processes requests in order specified by Handlers configuration element of IIS. By default Handlers element of the IIS configuration contains
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
at the end of the handlers. Therefore all request that not match any previously specified handler, will be processed by this handler (including folder request too).
You can remove all default handlers by using clear element in handlers configuration and specify your own request processing order.
I recommend to copy default IIS handlers configuration (C:\Windows\System32\inetsrv\config\applicationHost.config) to your web config without StaticFile handler at the end.
Then you should add specific static content handler for each static content type (jpg, gif, js, css).
<add name="StaticFile-swf" path="*.swf" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
<add name="StaticFile-png" path="*.png" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
<add name="StaticFile-gif" path="*.gif" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
<add name="StaticFile-jpg" path="*.jpg" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
<add name="StaticFile-css" path="*.css" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
<add name="StaticFile-js" path="*.js" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
and manged handler (PageHandlerFactory) for folder requests after that.
<add name="PageHandlerFactory-Folders" path="*" verb="*" type="System.Web.UI.PageHandlerFactory" modules="ManagedPipelineHandler" resourceType="Unspecified" requireAccess="Read" allowPathInfo="false" preCondition="integratedMode" />
At the end you should also add StaticFile handler.
Here is an example.

Removing preCondition="managedHandler" or adding <modules runAllManagedModulesForAllRequests="true"> should do it. The "Preconditions" section of this page has more information.

You can use a wild card script mapping, but it's inefficient to use the managed handler to handle all requests. The static handler is much more efficient when it is appropriate.

Related

Web.config equivalent to “using static MyClass;” in <add namespace=“MyClass” />

In ASP.Net, you can add a namespace to all Razor views by adding the following code to the View folder’s Web.config:
<system.web.webPages.razor>
<namespaces>
<add namespace=“MyClass” />
</namespaces>
</system.web.webPages.razor>
This is equivalent to putting the statement “using MyClass;” at the top of a C# file.
However, how would I add a namespace to Web.config as a “static” class, where I can access the class’s methods directly within views without having to write out “MyClass.MyMethod();” for example?
You can already do this by putting the statement “using static MyClass;” at the top of a C# file (C# 6 is required, see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-static).
It just appends whatever it is you put as namespace. Just needs to append the static keyword to the namespace.
So as you pointed out <add namespace=“MyClass” /> is equivalent to using MyClass;
Change to <add namespace=“static MyClass” />, which is equivalent to using static MyClass;
In your case:
<system.web.webPages.razor>
<namespaces>
<add namespace=“static MyClass” />
</namespaces>
</system.web.webPages.razor>
should be what you're looking for

How to use two connection strings on development vs production

I have two connection strings in my Web.config.
<connectionStrings>
<add name="AuthContext" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=mokey;Integrated Security=True" providerName="System.Data.SqlClient" />
<add name="AuthContextMySQL" providerName="MySql.Data.MySqlClient" connectionString="database=mokey;persistsecurityinfo=True" />
</connectionStrings>
I can specify which one to use in code like this:
public class AuthContext : IdentityDbContext<IdentityUser>
{
public AuthContext()
: base("AuthContextMySQL")
{
}
}
How do I specify which one to use depending on development vs production?
You can use web.config transformations during your build step to add/update/delete sections of your web.config depending on the build configuration. See this article for a step by step guide.

Mono WebService refuses to return json

I'm trying to create a web service using Mono 3.0.3.5 that returns json.
But so far I have been unable to get a service to return anything but xml. This appears to have been a matter of much discussion in the past, but even after checking my attempts against numerous resources here and elsewhere, I cannot tell what I'm omitting.
I created an empty ASP.NET solution, to which I added an asmx with codebehind page. As far as I'm aware, decorating the service class name with the ScriptService attribute and the method/function name with ScriptMethod and specifying Json for the ResponseFormat attribute are the only necessary steps in the code.
using System;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
namespace MonoJsonTest
{
[WebService]
[ScriptService]
public class GimmeJson : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat=ResponseFormat.Json)]
public string simpleTestString()
{
return DateTime.Now.ToString();
}
}
}
(I'm aware of the problems putting dates into json, I just wanted some string that would change with subsequent calls to my service)
Then I added System.Web.Extensions to the References of the project. This is built to .NET version 3.5, so I ensured that I included the 3.5 version of System.Web.Extensions.
Then the httpHandlers of web.config was modified to go through the ScriptHandlerFactory (as outlined on a couple of pages I've found)
http://vampirebasic.blogspot.com/2009/04/aspnet-ajax-in-mono.html
http://encosia.com/asmx-scriptservice-mistakes-installation-and-configuration/
A sharp eye might notice there is a difference in the web.config changes specified on the two pages. the "Culture=neutral" attribute is specified -inside- the string for the type attribute on the first page, but as an attribute of the add tag on the second. But I found that when specified the second way, there is an error upon starting the service.
My final web.config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation defaultLanguage="C#" debug="true">
<assemblies>
<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</assemblies>
</compilation>
<customErrors mode="RemoteOnly">
</customErrors>
<authentication mode="None">
</authentication>
<authorization>
<allow users="*" />
</authorization>
<httpHandlers>
<!-- should produce json responses -->
<remove verb="*" path="*.asmx" />
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpHandlers>
<trace enabled="false" localOnly="true" pageOutput="false" requestLimit="10" traceMode="SortByTime" />
<sessionState mode="InProc" cookieless="false" timeout="20" />
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
<pages>
</pages>
</system.web>
</configuration>
But hitting the service (locally) from the WSDL page or with an ajax query from javascript (using JQuery library) it always returns XML. Inspecting the response headers with both Charles and Firefox debugging tools shows me a response type of text/xml.
After research, it seemed I need to request json from the service when making the call, so I set the contentType, accepts, and dataType parameters of the ajax call to specify json but this made no difference. Strangely, even the request headers show the "Accepts" parameter is still specifying xml after I have explicitly set it in the Ajax call.
Here is the ajax call (note accepts and dataType type is set to json) :
$.ajax({
url: "http://localhost:8080/GimmeJson.asmx/simpleTestString",
type: "POST",
contentType: "application/json; charset=utf-8",
accepts: "application/json; charset=utf-8",
data: "{}",
dataType: "json",
success: function (data, textStatus, jqXHR) { console.log( "success" ); alert.show("success"); },
error: function(request, type, errorThrown) { console.log( "error" ); }
});
Here is the request header generated by that call (Accept is still xml):
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding:gzip,deflate
Accept-Language:en-us,en;q=0.5
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Host:localhost:8080
Origin:null
Pragma:no-cache
Proxy-Connection:keep-alive
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:14.0) Gecko/20100101 Firefox/14.0.1
This produces an HTTP code of 200, and this response header (note content type is xml):
Cache-Control:private
Content-Length:103
Content-Type:text/xml; charset=utf-8
Date:Thu, 09 Aug 2012 23:38:59 GMT
Keep-Alive:timeout=15, max=100
Proxy-Connection:Keep-alive
Server:Mono.WebServer2/0.2.0.0
UnixX-AspNet-Version:2.0.50727
One thing I have noticed that I'm not sure is an important point but seems odd. I browsed the System.Web.Extensions dll in Mono and noticed that a ScriptHandlerFactory did not seem to exist within it. Modifying the line in the web.config that adds the factory to specify "FOOScriptHandlerFactory" as the type did NOT produce any errors when starting the service, which would seem to indicate Mono is not reporting unfound types in the web.config. But I do not know enough about that aspect of .Net nor Mono to say that for certain. But as this factory is the lynchpin of the automatic Json serialization, this could be important.
I'm not sure what I'm omitting here. I feel like I haven't configured something on the server side correctly or it would be reporting json for the return type somewhere on the WSDL page. As you may have guessed I'm still new to online development, so my apologies if I'm overlooking Very Obvious Things.
Have you tried making the WebMethod static?
The other point I'd consider is whether the functions on the return could return 3 values instead of just one.

Azure role configuration management

I don't see how Windows Azure lets you vary the configuration of an application when you have no choice but to hold configuration settings in web.config (or app.config).
For example...
Quite often projects will make use of a 3rd party library that makes heavy use of web.config. The use of web.config may involve connection strings, app settings or custom configuration sections. A good example of this is ELMAH. A web.config file for ELMAH might look like the following:
<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
</sectionGroup>
</configSections>
<connectionStrings>
<add
name="MyElmahDatabase"
providerName="System.Data.SqlClient"
connectionString="Server=tcp:myServer.database.windows.net,1433;Database=myDB;User ID=user#myServer;Password=password;Trusted_Connection=False;Encrypt=True;Connection Timeout=30" />
</connectionStrings>
<elmah>
<security allowRemoteAccess="1" />
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="MyElmahDatabase" />
</elmah>
</configuration>
There are a couple of problems here:
There is no way for me to update or vary whether remote access is enabled between Service Configurations.
There is no way for me to update or vary the ELMAH connection string between Service Configurations.
This is because the web.config is packaged as is into the .cspkg file and ELMAH will not look at the Service Configuration settings (which are the only way I can vary configuration settings between Service Configurations).
I can think of many other examples where this is a problem...
Any data access frameworks that look directly at the connection strings section.
Any custom configuration settings I need to create.
...to name just two.
Am I missing something or is this a significant gap in the configuration management offered by Windows Azure?
EDIT
From the answer and comments below, it looks like this is something that is not well supported. I think that managing multiple solution build configurations to support different configuration profiles is a very weak solution. I should not have to rebuild the solution for each configuration profile I need (there will likely be quite a few). Compilation is not equal to configuration.
I was wondering if there was a way to modify the .cspkg file as it is just a zip file. According to this documentation you can on Linux.
I've looked at the manifest in the .cspkg file and it looks like this:
<PackageManifest version="2">
<Encryption keytype="1" />
<Contents hashtype="1">
<Item name="MyApp.Web.UI_<GUID>.cssx" hash="AED69299C5F89E060876BC16BD3D6DE5130F6E62FFD2B752BAF293435339B7E2" uri="/MyApp.Web.UI_<GUID>.cssx" />
<Item name="MyApp.Web.Services_<GUID>.cssx" hash="7AC81AFF642E4345173C8470C32A41118A4E3CFD4185B82D0ADA44B71057192D" uri="/MyApp.Web.Services_<GUID>.cssx" />
<Item name="SMPackage_<GUID>.csmx" hash="B5E6B83B62AF64C7C11CAC1A394ABBF15D7DB7667A773C5284CE5BE95C5834E9" uri="/SMPackage_<GUID>.csmx" />
<Item name="SDPackage_<GUID>.csdx" hash="F34B7C02A551D82BAD96881E2DA9447D0014D49B47CCB3840475BDC575234A7D" uri="/SDPackage_<GUID>.csdx" />
<Item name="NamedStreamPackage_<GUID>.csnsx" hash="FA2B5829FF5D9B2D69DCDDB0E5BDEE6B8B0BC09FFBF37DAEEE41CF3F3F4D0132" uri="/NamedStreamPackage_<GUID>.csnsx" />
</Contents>
<NamedStreams>
<Stream name="RequiredFeatures/MyApp.Web.Services/1.0" />
<Stream name="RequiredFeatures/MyApp.Web.UI/1.0" />
<Stream name="SupportData/MyApp.Web.Services/1.0" />
<Stream name="SupportData/MyApp.Web.UI/1.0" />
</NamedStreams>
</PackageManifest>
Unfortunately, if I re-compute the hash of the unchanged "MyApp.Web.UI_.cssx" file, my hash is different from the one in the manifest.
Hash from manifest: AED69299C5F89E060876BC16BD3D6DE5130F6E62FFD2B752BAF293435339B7E2
My calculated hash: E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
Note that I have not yet changed the file, so the hash should be the same.
This suggests I'm calculating it wrong. My method was as follows:
class Program
{
static void Main(string[] args)
{
using (FileStream fs = new FileStream(args[0], FileMode.Open))
{
ComputeHash(new SHA256Managed(), fs);
}
}
private static void ComputeHash(HashAlgorithm hashAlgorithm, Stream stream)
{
byte[] hash = hashAlgorithm.ComputeHash(stream);
string hashString = BitConverter.ToString(hash);
Console.WriteLine(hashString.Replace("-", string.Empty));
Console.WriteLine();
}
}
The documentation link above, suggests it is straightforward to re-calculate the hash (on Linux anyway).
Does anyone know how to re-compute the hashes?
Passing a Stream to ComputeHash() ends up with a different hash as compared to using the byte[] overload. I don't know why.
Try something like:
private static void ComputeHash(HashAlgorithm hashAlgorithm, Stream stream)
{
BinaryReader reader = new BinaryReader(stream)
byte[] hash = hashAlgorithm.ComputeHash( reader.ReadBytes( (int)stream.Length ) );
string hashString = BitConverter.ToString(hash);
Console.WriteLine(hashString.Replace("-", string.Empty));
Console.WriteLine();
}
This will give you the hash you're after.
As you've probably already discovered, on linux you can get the digest with
openssl dgst -sha256 /path/to/file
I you have items in your web.config that you want to change depending on how it's being built, there is a solution that is outside of Azure that you can use. You can use Web.config transforms. These transforms are tied to your build configuration not your service configuration, but your service configurations a likely closely tied to your build configurations anyway (...Local.csfg -> Debug, ...Cloud.csfg -> Release). If the default build configurations don't work for you, just create the ones you need.
If you want to use different service definitions per service configuration, then it's not supported by the UI, but you can mess around with the build process to make it work

How to send email in HTML format with Microsoft Enterprise Library?

I know how to send mails using the Microsoft Enterprise Library 2.0 using a text formatter. But these emails are always in plain text. Is there any way with entlib 2.0 to send these mails in HTML format?
Well that is funny, I am now writing my own answer.
What I did was use the source code of entlib.
Within
Microsoft.Practices.EnterpriseLibrary.Logging and
Microsoft.Practices.EnterpriseLibrary.Logging.TraceListenerData
I found the classes that I needed.
Copy EmailMessage.cs to EmailMessageHTML.cs
Copy EmailTraceListener.cs to EmailHTMLTraceListener.cs
Copy EmailTraceListenerData.cs to EmailHTMLTraceListenerData.cs
Put these classes in your own new Library Project.
Within EmailMessageHTML change all constructors to match the new classname and than ADD following line to the method:
protected MailMessage CreateMailMessage()
{
.....
message.IsBodyHtml = true;
.....
return message;
}
After that, I had to use this new EmailMessageHTML class in EmailHTMLTraceListener (change EmailMessage to EmailMessageHTML) and also use this EmailHTMLTraceListener in the new EmailHTMLTraceListenerData.cs file.
Compile this new project and than use this in your config as follows (example)
<loggingConfiguration
name="Logging Application Block"
tracingEnabled="true"
defaultCategory=""
logWarningsWhenNoCategoriesMatch="true">
<listeners>
<add toAddress="your#emailgoes.here"
fromAddress="yourserveraddress#goes.here"
subjectLineStarter=""
subjectLineEnder="My HTMLemailLogger"
smtpServer="localhost" smtpPort="25"
formatter="Text Formatter"
listenerDataType="MYLibrary.HTMLEmailLogger.EmailHTMLTraceListenerData,
MYLibrary.HTMLEmailLogger, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=null"
traceOutputOptions="None"
type="MYLibrary.HTMLEmailLogger.EmailHTMLTraceListener,
MYLibrary.HTMLEmailLogger,
Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=null"
name="EmailHTML TraceListener"/>
</listeners>
</loggingConfiguration>
and add a valid category to log this to of course:
<add switchValue="All" name="OutOfBalanceBooking">
<listeners>
<add name="Database Trace Listener"/>
<add name="EmailHTML TraceListener"/>
</listeners>
</add>
Of course you need some HTML document to than log with EntLib. I leave that as an exercise for the reader.
And indeed! I get a nice HTML email now for every outofbalance booking that customers make on the site...