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>
Related
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.
I have a standard ASP.NET MVC site with forms authentication.
Users log in via a web page. Then they can reach a silverlight app. When they log in, I pass them a forms auth cookie just like any other site:
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
The XAP file is in the ~/ClientBin/ folder. The SVC file is in the ~/Services/ folder. Anonymous access is blocked:
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
The Silverlight calls to the SVC results in a HTTP 302 bouncing back to the login page, and crashing the Silverlight. :( This only happens when anonymous access is disabled. I think Silverlight is NOT passing the cookie along with the WCF service call. Why not?
I made sure to use the AspNetCompatibilityRequirements as defined within the documentation (http://msdn.microsoft.com/en-us/library/dd560702(VS.95).aspx):
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class TaskSchedulerService : ITaskSchedulerService
{
and my web.config has
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
</system.serviceModel>
The same thing happens using basicHttpBinding or customBinding with BinaryCompression enabled.
Good news! I found the issue...
My silverlight application was programmed such that it would inject a dot "." into the URL when it called the web service on localhost
(http://localhost/myservice.svc -> http://localhost./myservice.svc).
I purposefully added this extra DOT so I could debug local traffic with fiddler. I removed the dot, and authentication works! The extra dot was percieved as a separate domain.
It turns out that WITH INTERNET EXPLORER 9, FIDDLER CAN DEBUG LOCAL TRAFFIC WITHOUT THE DOT.
As the MSDN Dcoumentation says:
To use the service from a Silverlight application, no special steps are required. Invoke the service in the same way as you would invoke a non-secure service. When calling the service, if the user is not logged in to the ASP.NET site that hosts your Silverlight application, or if the user is not authorized to call the service, an error will occur. Thus, it is especially important to gracefully handle error conditions when using secure services.
Bottom line: if you are developing silverlight, IE9 is your best friend.
I'm building a simple ASP.NET MVC 2.0 web application. I'd like to serve up a AtomPub endpoint so that I can publish/update content from Windows Live Writer. I originally went down the path of implementing the AtomPub protocol as an Controller with a set of custom ActionResults. That worked until I tried to get authentication working, when I realized that getting Basic or Digest auth (necessary for WLW) to work within my Forms-Auth based MVC app was going to be problematic.
So, now I've decided to move the AtomPub logic to a WCF service within the MVC app. I created a new WCF service called AtomPub.svc. I added the following to my web.config file:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
And, my AtomPub.svc.cs code behind looks like this:
namespace Web
{
using System.ServiceModel;
using System.ServiceModel.Web;
[ServiceContract]
public partial class AtomPub
{
[WebGet(UriTemplate = "?test={test}")]
[OperationContract]
public string DoWork(string test)
{
return test;
}
}
}
I also added a route exclusion to exclude this endpoint from MVC's route handling.
Now, I'm a total noob to WCF, so I'm sure I'm doing a number of things wrong. As I'm writing this, the root of the endpoint seems to be working as I get an AtomPub Service page. The URL templating, however, is not working and I don't know what to do to get it working. I'd love to hear your suggestions.
By the way, I'm trying to keep this overall implementation as simple as possible. So, I'm not looking to introduce a dependency on the Entity Framework so I can use WCF Data Services. I'd also prefer not to move the WCF endpoint into a separate project, though I'm open to that if I can easily deploy it to a W2k3/IIS6 environment.
OK, I found this article: RESTful WCF Services with No svc file and No config and it's pretty much gotten me up and working.
I have to use Sync Framework 2.0 in our WPF app that will contain SQL Compact 3.5 and will synchronize with SQL Server 2008.
I followed this video : http://download.microsoft.com/download/6/7/3/6730f0e7-a649-4656-96ab-150c7501a583/IntroToSyncServicesADODetNet_HighQuality.wmv.
But instead DataSet I've used EntityFramework 4.0 and C#.
I'm very interested in code auto generation by adding Local Database Cache file with extension sync. It is great, and I can modify code in my partial class to change base functionality.
Everything works grate when I have code for client and server place in WPF application.
Everything works grate when I use WCF Class Library that contains server synchronization logic.
But... In the following example they show us how to run solution and host WCF in local "WCF Host" only on my computer.
The first question is:
"How can I create instance of class from WCF Class Library that contains all server synchronization logic and then host it and expose in ASP.NET MVC 2.0 application."
The most important thing is to keep this *.sync files and don't write all the code manually it gives me the option to automatically update this code when database schema would change.
The second question is:
"How can I configure endpoints and behaviors for this instance of WCF Class Library in my web.config when it has its on app.config in class library?..."
Unfortunately wizard for *.sync files only sees local WPF application, or WCF Class Library, I can't choose directly ASP.NET MVC 2.0 (it would be great) to generate class for synchronization in web app.
I would be very pleased to see working example.
Regards,
Daniel Skowroński
Solution to create WCF Class Library instance with synchronization logic hosted in ASP.NET MVC 2.0:
follow http://download.microsoft.com/download/6/7/3/6730f0e7-a649-4656-96ab-150c7501a583/IntroToSyncServicesADODetNet_HighQuality.wmv to create WCF Class Library
create ASP.NET MVC 2.0 App and add WCF Service
delete C# file *.cs behind *.svc
add Project Referece from ASP.NET projet to WCF Class Library
edit your *.svc file in ASP.NET
here you will see something like:
<%# ServiceHost Language="C#" Debug="true" Service="namespace-assembly.class" CodeBehind="filename.svc.cs" %>
where Service is Factory method that will create instance of "namespace-assembly.class" so, you have to change this to "wcf_librrary_namespace-assembly.****DataCacheSyncService" and CodeBehind to "wcf_librrary_namespace-assembly.filename.cs"
next modify wcf instance in WCF Class Library that will enable hosting it with the same credentials as asp.net app, simply add : [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] attribute
next configure web.config:
<service name="asp.net-namespace.wcf_service_name" behaviorConfiguration="service_nameBehavior">
<host>
<baseAddresses>
<add baseAddress="http://ipaddres/asp.net-app-name/service-name.svc" />
</baseAddresses>
</host>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="" binding="basicHttpBinding" contract="wcf_librrary_namespace assembly.I****DataCacheSyncContract" />
</service>
<behavior name="service_nameBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
add also
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
below
<system.serviceModel>
now simply publish it to your server and create ASP.NET app
now add Service Reference to your Client Application
here we have problem that when you will execute:
**DataCacheSyncAgent syncAgent = new **DataCacheSyncAgent(new **DataCacheSyncContractClient());
Microsoft.Synchronization.Data.SyncStatistics syncStats = syncAgent.Synchronize();
You will probably get Exception: “Cannot convert type ** to Microsoft.Synchronization.Data.SyncGroupMetadata, One solution to resolve this issue for now that I’ve found is to expand your service reference and b CTR+H rename all “asp-net-assembly-SyncGroupMetadata” and other similar files to “Microsoft.Synchronization.Data.SyncGroupMetadata” etc.
Now synchronization should start
HTH
Regards,
Daniel Skowroński
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>