WCF DataService (OData) and CORS - c#

I am trying to get a WCF DataService working with cross domain requests.
I found this on how to get a WCF service to work with CORS:
http://blogs.microsoft.co.il/blogs/idof/archive/2011/07/02/cross-origin-resource-sharing-cors-and-wcf.aspx
I downloaded the sample, but can't get it to work with a DataService. It works with the sample service, but not with my DataService.
This is my very simple WCF DataService:
public class TestService : DataService<DataContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.UseVerboseErrors = true;
config.SetEntitySetAccessRule("Items", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
The TestService.svc file:
<%# ServiceHost Language="C#" Factory="WebHttpCors.CorsWebServiceHostFactory, WebHttpCors" Service="MvcApplication1.TestService" %>
The DataContext is also very simple:
public class DataContext : DbContext
{
public DbSet<Item> Items { get; set; }
}
But still, the preflight options request returns with a 501.
Is there something I am missing to get CORS to work with a Dataservice?

If you're using IIS, verify that the ExtensionLess handler is configured to handle the OPTIONS requests.
A few notes unrelated to your direct issue: since CORS is not properly supported, neither the package you found nor any other solutions will be truly satisfactory (you won't be able to easily specify your policies). It's possible to create a professionally-maintained package to do this using WCF inspectors, but I haven't seen any. Instead, I'd like to invite you to vote this up should you agree.
In the meantime, I can only recommend that you integrate any code you find on the web very carefully (as most of it is barely tested). This article may assist you with that. This is not directly related to Data Services, but it's the same WCF tech. Maybe look at the Web API implementation or other projects for inspiration.
Good luck.
PS: In 90% of the situations, you'll also want to forget about solutions involving proxying. In most architectures, it's just horrible and makes very little sense unless your edge backend is designed in a way that somehow would make it seem less kludgy.
Update: Also verify that the implementation you're using actually handles the OPTIONS requests properly. If it passes them through, WCF Data Services will return a 501, and the interceptor might just pass it back through as well even though the headers were set correctly. Since preflight requests don't need a body, a quick and dirty hack would be to pickup these 501s and change them into 200s, but obviously you really want to stop the request from hitting the data service in the first place.

Related

Health check, ASP.NET Web API

In my work I was asked to implement health checks into an ASP.NET Web API 2 written in C#. I have searched but all the documentation is for ASP.NET Core and its implementation, does anyone know how to implement health check featurs in the classic / full .NET Framework?
I agree with Igor. Here's a concrete application of what he suggested (obviously, there are other ways to do this, but this is the best way I know how to keep it clear and honor separation of concerns):
Create a new controller. In this example, I'll call it HealthController
Add an action to the controller, and annotate it with [HttpGet]
Place logic inside the action that checks for the stability of external dependencies. For example, if disk access is critical for your API, run a test or two to make sure that the disk is responding like you need it to. If you need to be able to query a database, make a sample query, and make sure it's successful. This part is completely custom and really depends on your API and how it needs to perform.
public class HealthController : ApiController
{
[HttpGet]
public IHttpActionResult Check()
{
// Add logic here to check dependencies
if (/* successful */)
{
return Ok();
}
return InternalServerError(); // Or whatever other HTTP status code is appropriate
}
}
Have an external service issue a GET request to your endpoint (currently at https://whatever.your.domain.is/Health/Check) and report back when it doesn't receive 200 OK for some amount of time.
I've used Amazon CloudWatch in the past and I've been happy with it. There are going to be other services out there that will do this for you, but I don't have any experience with them.

How to use SignalR 2 with WEB API, calling SignalR methods from API and from Clients

I've been struggling for the past two days on how to get SignalR 2 to work with Web API. I tried to follow a few tutorials, from Microsoft and from others, about the topic, but still took me time to understand where I was wrong. I'm posting this question to help someone else that ends up in the same situation I was on.
I needed to create a Hub on SignalR that could respond to a Console Application (C#) and a Web App (AngularJs) as clients, and I also needed it to send signals after a certain method on API being hit.
I followed these (and others) tutorials:
ASP.NET SignalR Hubs API Guide - Server (C#)
ASP.NET SignalR Hubs API Guide - .NET Client (C#)
Stream Web API Transactions Using SignalR
And some more, but those are the best I could find. Also, a dozen of others questions, here and on other sites.
The best I could come up with was a solution that only answered to the API method being hit, but the clients wasn't able to fire any of the Hub's methods (they could only listen to it).
This was my Hub's code:
public class MyHub : Hub
{
private static IHubContext hubContext =
GlobalHost.ConnectionManager.GetHubContext<MyHub>();
public static void GetStatus(string message)
{
hubContext.Clients.All.acknowledgeMessage($"GetStatus: {message}");
}
public void GetMessage(string message)
{
hubContext.Clients.User(id).acknowledgeMessage($"GetStatus: {message}");
}
}
And my question was: How can I make the clients hit those methods on Hub, so they can get some personal response, if needed?
Ok, so the main problem here was that somewhere when I started, I found out how to make the Hub respond to API's methods (I couldn't find where by the time I'm posting this answer), and then I only found different ways for the clients to call the Hub's methods, and one did not work with the other. I could not set both to the same way.
This is the code from my API's controller:
public IHttpActionResult TesteComunicacao(string mensagem)
{
MyHub.GetStatus("Message here!");
return Ok("ok");
}
And the Hub's method:
// Use this for Server Methods
public static void GetStatus(string message)
{
hubContext.Clients.All.acknowledgeMessage($"GetStatus: {message}");
}
This is the only way I found to make it happen. The hub will not respond with the method used by the clients. Those must have a different code, like this Hub's method here:
// Use this for Clients Methods
public void GetMessage(string message)
{
Clients.Caller.acknowledgeMessage($"GetMessage: {message}");
}
I was trying to implement my "hubContext" solution on the clients method, but it wasn't working at all, and when I tried to implement the "Clients" solution, later found, to be consumed by my API, I had to make it a "non-static method", and then call it on the controller, which only resulted in this error: "using hubcontext outside hub pipeline is unsoported"
And then, I found this blessed answer here on Stack Overflow, that finaly showed me where I was wrong.
And that's exactly what I was doing wrong. I must implement then differently based on the method's objective. The ones to be consumed by my API use "hubContext", and the ones to be consumed by my clients application use "Clients".
I hope it helps other people struggling with this problem to find it faster, since the blessed answer there was about ASP.NET MVC, not Web API.

How to properly make a call to a Web API

In the ASP .NET website they have an example of how to call a Web API from a .NET Client.
They have this method to make a call which creates a new Product:
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync("api/products", product);
response.EnsureSuccessStatusCode();
// Return the URI of the created resource.
return response.Headers.Location;
}
This is like the usual way to make any call to any API in any language or framework, but I see a lot of problems in this line:
HttpResponseMessage response = await client.PostAsJsonAsync("api/products", product);
If the "path" parameter is a string, there is no way to detect possible errors in compilation time. Besides, if the API changes and we have a lot of calls, there is no way to rebuild the calls quickly.
Is there a better way to build the call to avoid this kind of problems? I mean, like we do with Web Services, for instance.
Like Nkosi mentioned, that is how it is designed. However you could create a class with the API URI's and use those instead of literals
public class ApiUris
{
public const string Products = "api/products";
public const string Services = "api/services";
public const string Orders = "api/orders";
/* ... */
}
That way you can easily change the path if your webapi changes.
Even Web Service and WCF service does not gurantee build fail if the server changes the URL or type and/or structure of the parameter. You come to know about the changes only when you call the service and it breaks.
In case of calling Web APIs surely there is no way you can figure out that the URL or the paramemeter is incorrect until you call the API.
At the same time, Web API are not built to be changed frequently. If they are not reliable no one would use them. So if you are using an API you can be sure that they will not change their URL or stop supporting certain input parameters overnight making their consumer applications like yours break. They surely woudn't want to be sued by their customers.
Any API would change gradually and with well advanced notice to their customers so that they get time to change their implementation to support new version of API.
So you can rely on the service which you are using and puting values related to it (such as URLs) in the config file would be good enough. Or you can choose to put API Urls in database so that when it changes you just need to update entry in the database and changes will be effective immediately.
Just extending upon Adam's solution you can get a List of your routes using
System.Web.Routing.RouteTable.Routes.ToList();
Then getting the path depends on the concrete implementation of the RouteBase abstract class.

How can I host multiple IoC-driven WCF services in MVC?

I have around 6 WCF services that I want to host in an MVC application, routing requests to /services/foo to WcfFooService and /services/bar to WcfBarService
I can accomplish IoC with StructureMap within the services and inject my constructor dependencies by using the example that Jimmy Bogard blogged about here:
Jimmy's article is great, but I'm trying to extend it to work with multiple services hosted within the same MVC application. Essentially, the part at the bottom is the part that is causing me a few headaches:
public class StructureMapServiceHostFactory : ServiceHostFactory
{
public StructureMapServiceHostFactory()
{
ObjectFactory.Initialize(x => x.AddRegistry<FooRegistry>());
//var iTriedThisToo = ObjectFactory.Container;
//container.Configure(x => x.[etc]);
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new StructureMapServiceHost(serviceType, baseAddresses);
}
}
With a single WCF service - routing MVC requests to a specific url via the StructureMapServiceHostFactory shown above works brilliantly - but - If (for example) I create a StructureMapServiceHostFactory2 for the /services/bar call, to allow for a different Registry to be used, when the MVC app spins up, it appears to call each factory in turn as it runs through RouteConfig.cs and adds the routes, so ultimately I don't get configured instances that the first ServiceHostFactory should provide.
It doesn't make a difference if I call Initialize(); or attempt to grab the Container property and call Configure on it, either.
Am I on a hiding to nothing with this? The major reason for requiring registry isolation is due to different NHibernate configuration, but I could configure Named instances of SessionFactory and Session for NHibernate purposes and then use a single registry to get around this. In my mind I wanted the WCF service and MVC-hosting to be capable of using their own IoC containers in isolation, which is why I went down this route.
Is there any way that I can accomplish this?
Ok, so it would appear the only person capable of answering this was me, by virtue of a re-think and 're-architecting' the solution so that the problem doesn't exist in the first place.
I now have a capable way of hosting these services and maintaining IoC with StructureMap neatly per service, without any conflicting concerns.
If you find yourself in a similar position with SOA taking over (SOATO?) - taking a step back is a good start ;)

WCF Http RouteTables (for versioning)

I currently have something like this for my route table. Is there a nicer way to handle versioning in WCF Web API or conventional WCF?
RouteTable.Routes.MapServiceRoute<Service1>("1.0/Route1", Config1);
RouteTable.Routes.MapServiceRoute<Service2>("1.0/Route2", Config2);
RouteTable.Routes.MapServiceRoute<Service3>("1.0/Route3", Config3);
RouteTable.Routes.MapServiceRoute<Service4>("1.0/Route4", Config4);
You could do that, but it is very protocol-bound, in this case HTTP. I wonder if there is a way to do that without worrying so much about protocols? Ideally we only want to do it once and not for each transport out there. Luckily there is a way, let me explain.
At the end of the day, your WCF internals should be protocol agnostic. By that I mean by the time a method is invoked on your service, we should not care whether it came by REST, TCP, HTTP or named pipes.
In WCF this is pretty easy and so is versioning. With versioning we can learn much about .NET interface versioning particularly when it has nothing to do with WCF. The idea is that your service should realize:
interface ISomething1 { ... }
Later when a new method or changes are required you should:
interface ISomething2 : ISomething1 { void SomethingNew (...) }
It's then a simple matter to publish your service with 2 endpoints in config, one pointing to ISomething1 and the other to ISomething2.

Categories

Resources