Protocol Binding error with wildcard sub domains in Windows Azure websites - asp.net-mvc

I have multi tenant MVC application running as an Azure website. Tenants are resolved by using sub domains. So tenant A can be resolved by http://tenanta.myapp.com. This works perfectly well as long as I go and create individual CNAME records on my DNS server for each tenant. However I do not want to have to do this.
So I successfully added a wildcard A record *.myapp.com to my DNS records and in azure I added a custom domain name *.MyApp.com. So now I can use http://anything.myapp.com and it will resolved to my azure website ok. So that was great and I thought I was up and running.
Until I tried to browse to a page that is using AJAX to call a WCF service (the WCF service is internal to the website). There are a bunch of WCF services and they all throw a 500.
System.UriFormatException: The protocol binding '*:80:*.myapp.com' is not valid for 'http'. This might be because the port number is out of range.
If I remove the *.myapp.com from the list of custom domains in Azure then I don't get the error but my wildcard subdomains no longer get directed to the website and I get a 404 from azure.
I've tried a few things with the bindings for the WCF services including trying all of the HostNameComparisonMode options StrongWildcard, WeakWildcard and Exact.
I was hoping someone else had come accross this problem before. There are bunch of posts on getting the wildcard subdomains working but nothing specific to the issue I am having with WCF services.
Thanks in advance

This might be due to a binding of the shape :80:.myapp.com gets created in the applicaitonHost.config when the wildcard custom domain name is added to the site (in Azure Web Sites service). We will investigate and try to get this fixed.
Meanwhile, it might be worth a try to clear the bindings section in your web.config and recreate a binding of the form
<binding protocol="http" bindinginformation="*:80:"/>
Let me know if this works.

To add on Zhe's answer here is how it can be done:
Create an applicationHost.xdt file under your 'site' folder, and copy the content below into it
(more info on transform on Kudu site)
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.applicationHost>
<sites>
<site name="%XDT_SITENAME%" xdt:Locator="Match(name)">
<bindings>
<binding protocol="http" bindingInformation="'*:80:*.myapp.com" xdt:Locator="Match(bindingInformation)" xdt:Transform="Remove" />
</bindings>
</site>
</sites>
</system.applicationHost>
</configuration>

In azure, for custom domain name, add * instead of *.myapp.com and that should work.

Related

MVC bundles and IIS virtual directories (URL rewrite)

I'm hosting multiple applications on IIS server virtual directories and I'm using URL Rewrite to facilitate them. All images and other assets that are manually written like this "~/path/to/my/content" has a correct output "/path/to/my/content", but bundle paths like "~/client/js" gives an output "/myapplication/client/js" which should be "/client/js".
How can I fix that?
How I initiate Script bundle:
var scriptBundle = new ScriptBundle("~/client/js");
Rewrite configuration:
<rule name="Official Website" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^(www\.)?domain\.com$" ignoreCase="true" negate="false" />
</conditions>
<action type="Rewrite" url="officialsite/{R:1}" />
</rule>
Was looking into these topics, but couldn't make anything work for me:
How do I get System.Web.Optimization bundles to work with custom folders in an IIS virtual directory?
CssRewriteUrlTransform with or without virtual directory
Why does ResolveBundleUrl not work for custom folders? (MVC Beta 4)
Is it possible to unit test BundleConfig in MVC4?
UPDATE: I'm using Winhost as hosting provider, and they do not support setting up host headers for the IP, probably due to the shared IP. They provide domain pointers to root folders, which is why I'm using URL rewrite.
You said :
I'm hosting multiple applications on IIS server virtual directories
and I'm using URL Rewrite to facilitate them
So, The problem refers to root configuration (Virtual Directory) to be usable for bundling and etc.., It's not about bundling configuration or rewrite rule. I think you need to setup myapplication directory as virtual and set it up as a separate website. Make sure you have followed instructions available in Create Web Site where it says:
you add a Web site in IIS, a site entry is created in the
ApplicationHost.config file. The entry specifies:
network binding for the site
Maps the site to a location in the file system
optionally specifies user credentials for content access
To ensure that user requests reach the correct Web site, you must configure a unique identity for each site on the server.Web sites hosted on the same server can be distinguished using the following unique identifiers.
Host header name (recommended)
IP address
TCP port number
Configure a Host Header for a Web Site (IIS 7) points to the first one.
Update: I think there may be a name conflict on server and your project. more brightly try to change client in ~/client/js and its folder to new one. Unless there were multiple path choices (with this path depth) for server to fetch that you can solve it by adding an extra depth by adding an \ in your project and js bundle mapping.
Update2: Finally I suggest you to follow full article available in How to publish or host subdomain on winhost.com? to solve such this amazing issue :)
I have two options you can try.
1) Try using this to trick it into using the correct path:
var scriptBundle = new ScriptBundle("~/../client/js");
You may get an HttpException (Cannot use a leading .. to exit above
the top directory.), but it's worth a shot. I cannot replicate your
environment, so I cannot test.
2) Create your own virtual path provider:
Changing ASP.net application root?

Separating logs with filter in log4net only works for one value

I've got an ASP.NET MVC application using log4net on a Windows Server 2008 R2 and Window Server 2012. The application is installed as two separate instances with common code base, ie the log4net configuration file will be the same in both folder but I want to separate the logging to two different files depending on the hostname of the called web site.
I've tried setting up two different appenders with a property filter to filter out a value I set as seen below:
log4net.GlobalContext.Properties["site"] = HttpContext.Current.Request.Url.Host;
The filter for each appender in my log4net configuration file looks like this:
<filter type="log4net.Filter.PropertyFilter">
<key value="site" />
<StringToMatch value="hostnameA" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
The two web sites only share the common code, but have separate installation folders and separate application pools. Still only the web sites started first gets a working logger, the second doesn't log at all. If I IISRESET and then start web site B first and web site A second, then web site B (the first) works but not web site A.
I've tried both GlobalContext, ThreadContext and LogicalThreadContext, all with the same result. I've tried log4net 1.12.11 and 1.12.12.
Any tips?
Jonas
since you have two appenders logging into same file, one app will acquire a write lock on both and the other will fail.
My solution would be to add %processid to the log file name. That way, each process will always have it's own file at a given time - no conflicts. Try like this:
<file type="log4net.Util.PatternString" value="log-file-[%processid].txt" />
See http://logging.apache.org/log4net/release/sdk/log4net.Util.PatternString.html

Azure web role with two sites, cannot bind to two different endpoints

Inside a single azure web role, I have two endpoints. I have two sites, each one binding to different endpoints. Like this:
<WebRole name="MyWebRole">
<Endpoints>
<InputEndpoint name ="HttpIn" protocol="http" port="80"/>
<InputEndpoint name="HttpsIn" protocol="https" port="443" certificate="Certificate1" />
</Endpoints>
<Sites>
<Site name="Web">
<Bindings>
<Binding name ="HttpsIn" endpointName="HttpsIn"/>
</Bindings>
</Site>
<Site name="Open" physicalDirectory="..\..\NotSecure">
<Bindings>
<Binding name ="HttpIn" endpointName="HttpIn"/>
</Bindings>
</Site>
</Sites>
When running this in the debugger, I get an error saying
"There was an error attaching the debugger to the IIS worker process for URL "http://127.255.0.0:82" for role instance ....
ok, so looking in IIS manager, I find the deployment. Click: http://127.255.0.0:82/ on browse. It comes up fine. Browse to the other one. The site comes up, too.
However, acknowledging the error stops the debugger and deletes the deployment.
Is this sort of configuration not allowed? Would rather avoid virtual directories. Just want two very different web sites to run based on http or https, on the same domain. What's missing?
There is a trick that is not mentioned in very many places. If you have a site with a name of Web some of the information is overridden with default values, including some of the binding information. Try changing the name of your first site to be something else like "Secure".

Is it possible to consume WCF service from same project?

I have an ASP.NET MVC 3 application that uses a WCF service within the same project. Ideally I'd like to call out to this service using jQuery. However, I cannot seem to wrap my head around what I'm doing. Should I still create an endpoint in the configuration? Right now I receive the following exception:
Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.
I can enable anonymous authentication for IIS but I'd prefer to use Windows. When I setup a binding configuration, since there is no endpoint, I'm not sure where to add that configuration to.
If you want to be able to reach your WCF service, you will generally need to setup an endpoint. An alternative approach would be to host your service "In-Proc" using the InProcFactory clas, which is part of the ServiceModelEx library from Juval Löwy available from the downloads page of his website (registration is required to download it, just search for "ServiceModelEx" and click the link). That approach would look like:
IMyService proxy = InProcFactory.CreateInstance<MyServiceClass, IMyService>();
proxy.MyMethod();
This reduces the configuration if you don't need to do any custom configuration; however, as soon as you hit a boundary with the default configuration, you'll either need to go back to using a configured endpoint, or looking for a way to programmatically update your service's configuration.
You'll need an endpoint, but as with all WCF endpoints it doesn't necessarily need to be defined in the config file - you're free to define it in code.
As you're already in a web project, your simplest solution will be to host the WCF service in IIS. This works very easily with a config file, and in .NET 4 most of the configuration is defaulted (a lot simpler than 3.5)
Once your service is defined you need to instantiate a channel or a client. You can use the svcutil tool to generate a proxy (using the 'Add New Service Reference...' wizard), or just create a ChannelFactory
var factory = new ChannelFactory<MyService>(typeof(MyService).FullName);
MyService channel = factory.CreateChannel();
// use the channel as you would a normal instance of the class
var result = channel.MyOperation("hello world");
Again, this pattern will retrieve configuration from your web.config file. Because your project is both the service and the client, you'll need both sections. This isn't a complete configuration but should give you the idea...
<system.serviceModel>
<services>
<service name="MyProject.MyService">
<endpoint binding="basicHttpBinding"
contract="MyProject.IMyService" />
</service>
</services>
<client>
<endpoint name="MyProject.MyService"
address="http://localhost"
binding="basicHttpBinding"
contract="MyProject.IMyService" />
</client>
</system.serviceModel>

How can I expose a WCF Service in a Virtual Directory w/o Forms Authentication?

My group builds internally hosted ASP.NET MVC websites with forms-authentication.
I'd like to host a WCF service in the same virtual directory as an ASP.NET MVC website.
My Question:
How do I make the WCF service freely
accessible, that is without
forms-authentication.
My current predicament is this:
I can access the .svc and see the wsdl information if I first authenticate through forms-authentication with a web browser.
But when I try to access the WCF service with wcfTestClient.exe, I get the following error:
Error: Cannot obtain Metadata from
http://localhost/Services/MyService.svc
If this is a Windows (R) Communication
Foundation service to which you have
access, please check that you have
enabled metadata publishing at the
specified address. For help enabling
metadata publishing, please refer to
the MSDN documentation at
http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata
Exchange Error
Do you have a mex endpoint defined in your web.config for the service? The testclient is likely looking for this.
IF you do, one other possibility is to disable authorization on the services folder. I've never tested this, but in theory it may work...
So if website is localhost, put WCF service in localhost/services/myservice.svc or the like. Then add a web.config to the /services folder, which overrides the authorization and allows all:
<configuration>
<authorization>
<allow users="*" />
</authorization>
</configuration>
If you can put your .svc file into a subfolder of the virtual directory, you can leverage the path attribute in Forms Authentication to enable access to it with a different level of authorization. Here is a tutorial.
Many thanks to all who tried to answer this question.
After hours of troubleshooting this problem, I discovered that a custom authentication module was rejecting my client attempts to get the metadata. Suffice it to say, I needed to route around this logic.
Oh - And stepping through the code is very underrated. ;)
I assume since you are using forms authentication that the virtual directory is configured for anonymous access in IIS. With that said, If you place your WCF service e.g. *.svc file in its own directory, you can update the main web.config file and add a location tag to disable forms authentication for the directory containing the service. Also be sure to disbale security via the WCF configuration binding settings in the web.config's <system.servicemodel> section which needs to be added if not already present:
<bindings>
<wsHttpBinding> <!-- one of many possible bindings -->
<binding name="...">
<security mode="None"> <-- allows anonymous access -->
<message clientCredentialType="None"/> <-- allows anonymous access -->
</security>
</binding>
</wsHttpBinding>
</bindings>

Resources