WCFService's DBContext to MVC App? - asp.net

I have created a 'WCFService' application under 'WCFSolution' solution and generated the DBContext using Entity Framework from a Database 'DemoDB' in 'WCFService' application. and also created some CRUD methods in WCFService (Which is working great).
Then I created an empty 'WCFMVCApp' MVC application under the same solution ('WCFSolution') and also added the service reference to this app. Now i needed to create a controller ('HomeController') with the DBContext that is generated in that WCFService, so that i can generate the views based on the WCF models while creating the controller.
I could create a new EF in WCFMVCApp but it would defeat the purpose of WCF. Any way to do this. or is it possible? Any help would be appreciated. Thank you.

If you are using a WCF Service, in your MVCProject you don't have a DbContext to deal with and you should not add a reference to your WCF Service. You have some options.
Solution 1: Use a client
In your MVC Project create a data service client. Your service should be running and you need the data service tools installed. Then you can add a service reference and some proxy classes are generated for you.
WCF Data Services 5.6.0 RTM Tools Installer
Solution 2: Add a DbContext dll
You can have your DbContext living in a seperate class library that you reference in your service and your MVC project.
In both cases you are using DataServiceContext to perform CRUD operations. For the second one you may have to add an an implementation for ResolveType. To get an idea how to do this, this is how the automatic generated DataServiceContext would resolve types:
ODataSamples
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.1.0")]
public Container(global::System.Uri serviceRoot) :
base(serviceRoot, global::Microsoft.OData.Client.ODataProtocolVersion.V4)
{
....
this.ResolveType = new global::System.Func<string, global::System.Type>(this.ResolveTypeFromName);
....
}
/// <summary>
/// Since the namespace configured for this service reference
/// in Visual Studio is different from the one indicated in the
/// server schema, use type-mappers to map between the two.
/// </summary>
protected string ResolveNameFromType(global::System.Type clientType)
{
global::Microsoft.OData.Client.OriginalNameAttribute originalNameAttribute = (global::Microsoft.OData.Client.OriginalNameAttribute)global::System.Linq.Enumerable.SingleOrDefault(global::Microsoft.OData.Client.Utility.GetCustomAttributes(clientType, typeof(global::Microsoft.OData.Client.OriginalNameAttribute), true));
if (clientType.Namespace.Equals("ODataSamples.CustomFormatService", global::System.StringComparison.Ordinal))
{
if (originalNameAttribute != null)
{
return string.Concat("ODataSamples.CustomFormatService.", originalNameAttribute.OriginalName);
}
return string.Concat("ODataSamples.CustomFormatService.", clientType.Name);
}
return null;
}

Related

Areas in self-hosted (OWIN) Web API

I'm setting up a new web application. We have services that perform continous background operations (CQRS projections), which is why we host them in windows services. We'd like to use these services to host the corresponding web APIs as well (otherwise we couldn't serve in-memory projections).
In addition, we'd like to have SignalR support to inform the clients whenever a projection was updated. We have a separate ASP.NET MVC application because we use Razor views for templating.
We'd like to split the web API into several areas - similar to how it's possible to do in an ASP.NET (MVC) application - with one area per bounded context. Such as http://localhost:8080/Orders/api/{Controller}/{id} or http://localhost:8080/Foo/api/{Controller}/{id}
At a later point we'd also like to have the controllers, projections, models etc. in separate assemblies. Again, one per context
Is it possible to define areas in a self-hosted Web API project? Would it perhaps be possible to route them to controllers from specific assemblies?
Thanks to the article in https://blogs.msdn.microsoft.com/webdev/2013/03/07/asp-net-web-api-using-namespaces-to-version-web-apis/ I've solved it.
I have to implement my own IHttpControllerSelector and replace the default one in Startup.cs like so:
/// <summary>
/// OWIN startup class
/// </summary>
public class Startup
{
/// <summary>
/// Owin configuration
/// </summary>
/// <param name="app">App builder</param>
public void Configuration(IAppBuilder app)
{
// We might have to resolve the referenced assemblies here or else we won't find them. This is a quick and dirty way to make sure that the assembly containing the controller has been loaded
var x = typeof(CarRental.Reservations.Application.Read.Web.FooController);
// Configure Web API for self-host.
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{boundedcontext}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Enable routing via bounded context
config.Services.Replace(typeof(IHttpControllerSelector), new BoundedContextControllerSelector(config));
app.UseWebApi(config);
// Configure SignalR
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
With BoundedContextControllerSelector being an implementation of IHttpControllerSelector very close to the code in the example: https://aspnet.codeplex.com/SourceControl/changeset/view/dd207952fa86#Samples/WebApi/NamespaceControllerSelector/NamespaceHttpControllerSelector.cs
I use the namespace to determine the bounded context and now have a clear separation of web api endpoints for each context :)

Web API 2 Scaffolded controller's routing vs empty controller's routing

As you know Visual Studio provides scaffolding for MVC and Web API controllers. In my case I'm using Entity Framework along with Web API 2.
When I add a new web api 2 controller with actions using Entity Framework, Visual Studio pretty much creates a controller with 5 endpoints.
One of these endpoints is to retrieve a single record from the database.
Here is an example for that:
// GET: api/Courses/5
[ResponseType(typeof(Course))]
public async Task<IHttpActionResult> GetCourse(int id)
{
Course course = await _db.Courses.FindAsync(id);
if (course == null)
{
return NotFound();
}
return Ok(course);
}
The above controller works fine if I call it as api/Courses/5, but it also works fine if I call it as api/Courses?id=5.
My question is, if I add an empty Web API 2 controller, define these methods manually along with some other endpoints, I can either call the endpoint like the first call or the second call, but not both.
Is there a way to set up routing of an endpoint which would accept both options?
PS: I know how to separately set up routing for each of above options. My question is whether it is possible to set up for both.

Why is accessing session state and HttpContext in WebAPI considered bad design?

I have several .asmx web services that I want to upgrade to WebAPI. These web services look somewhat like this:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class TheWebService : System.Web.Services.WebService {
[WebMethod(EnableSession = true)]
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = HttpContext.Current.Session["UserSession"] as MySessionModel;
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
Basically, I have a single-page application. I'm using Forms Auth to login and redirect users to their "profile" and then, from this page, the app uses web services to communicate with the server. The web services only return raw strings so I don't need serialization at teh web service level. For the moment, the app is hosted in IIS and soon I'll be deploying it into azure.
I've looked around on the web, and several posts suggest that using session state and HttpContext is bad design. Why is using HttpCurrent and session state a bad idea in this case?
There is nothing innately wrong with using ASP.NET Session, as long as you don't use it as a catch-all basket for any old data. Shopping carts, for example, do not belong in Session: they belong in a Shopping Cart persistence component.
Also, and I suspect the reason for the Azure tag on this question, if you are running in a load-balanced environment such as an Azure Cloud Service, you need to use an external session provider such as a SQL Database or a shared cache. Using the in-process session provider (the default) will cause very odd, often unreproducable bugs as users are switched between different servers with different copies of the session.
As for HttpContext.Current, well, for Web API, things like Inversion of Control, Dependency Injection, and simple testability are important. A clean, testable Web API version of that service might look something like this:
public class TheWebService : ApiController {
private readonly IUserSession _userSession;
public TheWebService(IUserSession userSession)
{
_userSession = userSession;
}
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = _userSession.Get();
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
public interface IUserSession
{
MySessionModel Get();
}
You could still use HttpContext.Current.Session["UserSession"] in a class like this:
public class CurrentContextUserSession : IUserSession
{
public MySessionModel Get()
{
return HttpContext.Current.Session["UserSession"] as MySessionModel;
}
}
You would then use an IoC container such as Unity or Ninject to set CurrentContextUserSession as the implementation of IUserSession for Web API to use when constructing instances of TheWebService. But when you were writing your tests, you could use a mock or stub implementation of IUserSession that had no dependency on HttpContext.Current.
In your specific example, you are using the Session only inside the WebMethod, which is fine as it is already coupled to ASP.NET but many people tend to use this at other layers of their application which is a really bad design.
Common problems of using HttpContext.Current in those layers are:
the code cannot be easily unit tested in isolation
the code is tightly coupled to an ASP.NET context
This being said, having stateful services that depend on the session is bad design. In the example you have shown, that's an ASMX WebService which is depending on the ASP.NET Session state meaning that the client should be passing cookies around in order to invoke this service. Also stateful services are harder to scale.

How to mix Entity Framework with Web API

I'm researching the new ASP.NET MVC4 Web API framework. I'm running Visual Studio 2011 beta on the Windows 8 consumer preview.
My problem is that none of the official samples for the new Web API framework use any kind of database backend. In the past, I've been able to create a local SQL CE database and serve it up via a WCF Data Service using Entity Framework as the ORM. How do I do the same with Web API?
Also, is this even a valid question? Should I just keep using a WCF Data Service if I want to expose an Entity Framework mapped SQL CE database? It seems to work fine, other than not offering the flexibility to choose response formatters that I might get with web api.
If you look at the official Contact Manager sample, you'll find that the Repository Pattern is used to access the data layer.
Also, bear in mind that in this particular example there's also DI via Ninject.
In my case I've easily plugged this onto an already existing EF model.
Here's an example for a repository implementation
///MODEL
public class SampleRepository : ISampleRepository
{
public IQueryable<Users> GetAll()
{
SampleContext db = new SampleContext();
return db.users;
}
[...]
}
///CONTROLLER
private readonly ISampleRepository repository;
public SampleController(ISampleRepository repository)
{
this.repository = repository;
}
//GET /data
public class SampleController : ApiController
{
public IEnumerable<DataDTO> Get()
{
var result = repository.GetAll();
if (result.Count > 0)
{
return result;
}
var response = new HttpResponseMessage(HttpStatusCode.NotFound);
response.Content = new StringContent("Unable to find any result to match your query");
throw new HttpResponseException(response);
}
}
Your mileage may vary though, and you might want to abstract out some of this data access even further.
Good news is that plenty of patterns and ideas that you may have already used on MVC-based projects are still valid.
I haven't worked with WCF Web API, so I can say for sure if you can use it same way as you did with WCF Web API, but I'm sure you can use EF with ASP.NET Web API. I suggest you take a look at how ASP.NET MVC makes use of EF, it should be very similar how you would use it with ASP.NET Web API.
As for other question, if you're planning some new development you should consider using ASP.NET Web API since there's an announcement on wcf.codeplex.com saying:
WCF Web API is now ASP.NET Web API! ASP.NET Web API released with
ASP.NET MVC 4 Beta. The WCF Web API and WCF Support for jQuery content
on this site will be removed by the end of 2012.

WCF Data Service as Library

Today I am digging into WCF Data Service and I have a question regarding this. Can I create WCF Data service as Library and just only create WCF data Service in our existing web app and take reference that library using Factory property so service will deploy with existing web application.
As I know We can create WCF Service Library and only need to take reference that library in Web application like :
Create a WCF Library and implement service contract
Create a Web application and add new item as Wcf service file then take reference WCF library
<%# ServiceHost Service="MyServiceLibrary.MyService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" />
Instead of a service library, I want to create OData service library.
Thanks
Yes, you can host a WCF Data Service in your own assembly - with a few little tricks. I researched this a while ago and came up with these steps / instructions.
Here's how:
put your data model (EF Data Model) into its own assembly, let's call it DataModel
create a new class library project (call it MyDataServiceHost)
add a few references:
your DataModel assembly with the data layer
System.ServiceModel
System.ServiceModel.Web
System.Data.Services.Client
System.Data.Services - you cannot pick this from the usual Add Reference dialog under the .NET category - you need to browse for the assembly file. Find the directory C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0 (or C:\Program Files (x86)\... on a 64-bit machine) and pick the System.Data.Services.dll inside it
add a new class to that class library and call it e.g. YourDataService.cs - it will look something like this:
using System.Data.Services;
using System.Data.Services.Common;
using DataModel;
namespace MyDataServiceHost
{
public class YourDataService : DataService<YourModelEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
You can name the class anything you like, and it has to derive from DataService<T> where T is the name of your data model; if you're using Entity Framework, it's the name of your object context class - typically something like (database)Entities or whatever you picked when you created the EDM
add another class to your new project, call it MyDataServiceHost.cs and it will look something like this:
using System;
using System.Data.Services;
using DataModel;
namespace MyDataServiceHost
{
public class MyDataServiceHost
{
public static void LaunchDataService(string baseAddress)
{
Uri[] baseAddresses = new Uri[1];
baseAddresses[0] = new Uri(baseAddress);
using(DataServiceHost host = new DataServiceHost(typeof(YourDataService), baseAddresses))
{
host.Open();
Console.WriteLine("DataService up and running.....");
Console.ReadLine();
host.Close();
}
}
}
}
It instantiates a DataServiceHost, which is derived from WebServiceHost (which in turn is derived from ServiceHost) and it will spin up the WCF Data Service runtime for you.
now you can start up your WCF Data Service from any app using:
MyDataServiceHost.LaunchDataService("http://localhost:4444/YourService");
last thing to remember: the app that you use to launch the WCF Data Service must have the connection string (the EDM connection string, if you're using Entity Framework) in its app.config (or web.config) in order for this to work!

Resources