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

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".

Related

Protocol Binding error with wildcard sub domains in Windows Azure websites

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.

ASP.NET MVC Does the WCF service reference/proxy have to exist in the web app assembly?

We want our web applications separated from our WCF web services. We don't want the web app to know if it's hitting any WCF services. Therefore we don't want any WCF web service references defined in the web app assembly.
What I'm trying to do is create a separate WCF wrapper assembly that would contain the WCF service reference and the necessary configuration in the app.config file. Method in the WCF wrapper would be called from the Web app. When I create the WCF service reference and configuration in the Web App assembly it works fine. When I put the WCF web reference and config file in WCF wrapper assembly it complains about not finding the endpoint. It doesn't look like it's finding the app.config file in the wrapper assembly.
So in summary I want a structure as follows:
Web app --> WCF wrapper (with WCF service references and config) --> BAL layer --> etc
Config file (web.config if in web app assembly, app.config if in WCF wrapper assembly):
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IEmailValidator" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8080/" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IEmailValidator" contract="EmailProxy.IEmailValidator"
name="BasicHttpBinding_IEmailValidator" />
</client>
</system.serviceModel>
Do I have to create the WCF service references in the web app assembly or can I do it in the WCF wrapper?
Error Message:
Could not find default endpoint element that references contract
'EmailProxy.IEmailValidator' in the ServiceModel client configuration
section. This might be because no configuration file was found for
your application, or because no endpoint element matching this
contract could be found in the client element.
This goes back to the old truth that the .NET configuration system doesn't support config files for class libraries - it expects the config for a class library to be in the host application that uses the class library - e.g. in your web application.
It's really not a WCF problem - it's a general .NET design decision that the .NET team made. A class library might have an app.config file in the solution, and that might even be compiled into a myclasslibrary.dll.config - but that file is not inspected and parsed by the .NET configuration system.
Therefore, in your case, your web app cannot find the config and thus cannot configure any endpoints and that's why it fails.
You basically have three major options:
live with this restriction and put your WCF config into the web app's web.config
find an alternate way to configure your WCF service library, e.g. from some other source, like a database
invest a lot of effort into making your WCF service library actually look into and pick up your class library's separate config file
You can load a custom config file via
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = #"c:\myapp\wcfsettings.config.anything";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);

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>

ASP.NET MVC Web Config Email Settings

I'm trying to include some SMTP settings in my ASP.NET MVC project by adding the following to my Web.Config file:
<system.net>
<mailSettings>
<smtp>
<network
host="host"
port="25"
userName="username"
password="password" />
</smtp>
</mailSettings>
</system.net>
This usually works for me in a standard ASP.NET application however in MVC, it's causing my site to render as blank (no source code in the browser atall).
My application builds ok so I assume I'm just missing a key piece in the MVC model.
Turns out that the answer is to include the settings inside of the <configSections>, after the <sectionGroup> section.
Putting the code before the <sectionGroup> tagset seems to result in the blank result I was experiencing.
I got an error when I put this in the <ConfigSections> group, however it worked when I put it immedietly after </ConfigSections>. Are you sure you didn't put it outside the <configSections>?

Resources