EF DbContext in WCF Services - wcf

I am creating an application that uses EF as its data access orm.
My entities are losing its state, causing that whenever I save a new entity, any objects in relationships are marked as new and try to be inserted as well.
How do I instance my DbContext once per WCF call so I use the same context in the whole service call and prevent it from bieng disposed and let my entities with an inconsistent state?
I used to store the context in the HttpContext when I did web apps, but in WCF there is no such thing as HttpContext.
Where can I store it so is used per call?
Thanks!

You can use HttpContext in WCF.
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
I usually cache my DbContext in HttpContext using structuremap's HybridHttpOrThreadLocalScoped:
For<IDbContext>().HybridHttpOrThreadLocalScoped().Use(() => new MyDbContext());
This can be done manually using HttpContext.Current.Items.
I suppose it could be done differently in pure WCF but it's ok to use aspNetCompatibilityEnabled - imo.
Cheers!

Related

ASP.Net Framework 4.0 WCF Concurrency

I am new to WCF, I am facing concurrency related issue in my hosted wcf service (.net framework 4.0) on IIS 7 / Windows 2008 server. I did all the possibilities after googling but still not able to fix my problem. I have created and inventory service which uses Entity Framework to fetch data from SQL Server tables like ItemHeadMaster, ItemMaster etc.
I referenced this WCF in my custom user search control for searching purposes. All is running well when 2 concurrent user hit search control placed on ASP.Net page.
My code looks like this:
namespace HIS.STORESERVICES
{
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class StoreMasterData : IStoreMasterData
{
public string GetAllItemHead(string strHospitalId)
{
using (DAL.ItemHeadMaster objItemHeadMasterDAL = new DAL.ItemHeadMaster())
{
List<STORE.MODEL.ItemHeadMaster> objItemHeamMasterList = new List<STORE.MODEL.ItemHeadMaster>();
objItemHeamMasterList = objItemHeadMasterDAL.GetAllItemHead(strHospitalId);
XmlSerializer Xml_Serializer = new XmlSerializer(objItemHeamMasterList.GetType());
StringWriter Writer = new StringWriter();
Xml_Serializer.Serialize(Writer, objItemHeamMasterList);
return Writer.ToString();
}
}
}
I did following after googling:
added in config but NO EFFECT
<system.net>
<connectionManagement>
<add address="*" maxconnection="100" />
</connectionManagement>
</system.net>`
Added in config but NO EFFECT instead it gets more slow..
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceThrottling maxConcurrentCalls="32"
maxConcurrentInstances="2147483647"
maxConcurrentSessions="20"/>
Please help
Before WCF, to construct a service for cross process communications between processes in the same host, or in the same LAN, or in the Internet, you have to hand-craft transportation layers and data serializations for target environments and specific protocols.
With WCF, you just need to focus on creating data models (DataContracts after being decorated by attributes) and operation models (OperationContracts), and .NET CLR will "create" most if not all needed transportation layers and data serializations at run time, according to the configuration defined by you or the system administration in the target environment.
The defects in your codes:
WCF typically uses DataContractSerializer, NOT Xmlserializer to serialize things, and you don't need to call it explicitly, since the runtime will do it.
For most applications, you don't need ServiceBehaviorAttribute explicitly. You must know WCF in depth before using those advantage config which is not for beginner. And I rarely used them.
Your service interface function should comfortably return complex type rather the serialized text. In 99.9% of cases, if you have explicit serialization codes in WCF programs, the whole design is very dirty if not entirely wrong.
There are plenty of tutorials of creating Hello World WCF projects, and VS has one for you when creating a new WCF application. After you got familiar with Hello World, you may have a look at http://www.codeproject.com/Articles/627240/WCF-for-the-Real-World-Not-Hello-World
BTW, WCF serialization is very fast, check http://webandlife.blogspot.com.au/2014/05/performances-of-deep-cloning-and.html

ServiceHostFactory using Structuremap that relies on HttpContext

I have an existing Structuremap ApplicationRegistry that relies on HttpContext.Current.Server and also HttpContext.Current.Items (via HttpContextScoped). I'd like to use this in my WCF ServiceHostFactory, but HttpContext.Current remains belligerently null.
I am using basicHttpBinding and for the scope of the project I'm working on I'm happy to continue to rely on that being used. My understanding is that if you use basicHttpBinding you should be able to use HttpContext.Current. Since this is always null I've obviously missed something.
What might that be?
The solution was to add this attribute to my service class:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

nHibernate + wcf + Isession

I have a c# solution with 3 projects - Data, WCF and UI. The first one is a class library that talks to db. It's exposed via the second one, which is of type WCF Service Library - the reason for that is it will be exposed in third project - Asp.net app called UI - as a simple svc pointing to dll.
Just to point it out, I'm not using Repository pattern.
I need to have ISession for a WCF call (similiar to Session-per-request approach for asp.net). Can anyone share a solution that simply works? I don't want to use any IOC for that.
Use WcfOperationSessionContext (new in 3.0).
Once bound, your Data classes just have to use SessionFactory.GetCurrentSession().
Each call to service is associated with unique OperationContext. OperationContext doesn't have any store for custom objects but you can implement extension. By setting session in MessageInspector you can initiate NHibernate Session per call in centralized place and access your extended context in any operation.

WCF Design Approach

In my solution I have a Web application project and a Class library project that contains all the business logic and this also acts as a data access layer as I am using Entity Framework. This means that I have my edmx in this layer itself.
I have some 34 classes in this class library project and at an average 6 public methods in each class. These classes were getting called directly from the web application until now. No problems. Now I want to introduce the WCF Layer between the UI and the Business logic layer.
This means I will have to write wrapper methods for all my methods and expose them in a WCF Service. Does this mean that 34 * 6 = 204 methods (approximately) will appear in my service layer as Operation Contracts? As per OO, I think this is too large a class and so it feels wrong.
I know there is the Generic Service design pattern, but is there anything else that I am missing? Please advise.
You could try RIA services
http://www.silverlight.net/getstarted/riaservices/
What I'm using is this.
Create a WCF service
2.1. Point the SVC service to your implementation like:
<%# ServiceHost Language="C#" Debug="true" Service="BusinessLayer.Service" %>
BusinessLayer.Service is a class in your Class project. (reference in service is needed)
2.2. Point the service behavior to the contract:
<service behaviorConfiguration="ServiceBehavior" name="BusinessLayer.Service">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding" contract="BusinessLayer.IService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</service>
Edit the name (BusinessLayer.Service) and contract (Businesslayer.IService)
Create the contract interface BusinessLayer.IService (in your Class project):
namespace BusinessLayer
{
[ServiceContract]
public interface IService
{
[OperationContract]
void DoWork();
}
}
Modify the existing implementation which uses the interface (here is your existing code):
namespace BusinessLayer
{
public class Service:IService
{
Public void DoWork()
{
}
}
}
Why do you want to wrap the entire business logic layer in a WCF layer? I would look very closely at your reasons for this before jumping into this new approach. Do you have physical reasons that you simply can't get around like the business logic that accesses the database needing to be outside the DMZ? If so, ok. But if not, I'd think twice about going down this approach to start with.
Having said that, if you have no other choice, I'd avoid the monolithic WCF class that wraps every public method that your UI needs. First off, I'd introduce an interface on the web application side so that you can depend on abstracts in the UI rather than concrete implementations. Further, I'd look into using WCF REST services. You can use ServiceRoute's to avoid having to introduce any *.svc files. Then you can decorate the methods you want to expose with WebGet/WebInvoke attributes. This could potentially save a lot of coding.
Well,
We have a similar application but the number of classes is even higher. Your concern here is that you are reluctant to provide serialization (that is what is needed to pass objects by WCF) to core classes of your business logic server.
Provided you have a classical three-tier application where business logic server and a client access the same database. What you need to do is simply 1) ensure all your objects have a unique identification (this could be a string or Guid) and 2) pass object ID in all WCF calls. What that means is that you DO NOT expose any classes on WCF side.
This might be quite is safer since you have a web application.
It is wrong. Your services should not have much more than 20 operations. If you need exactly same operations you should create contract and service wrapper for each business class. This usually results in chatty interfaces which are not good solution for distributed scenario. In that case you should model your service layer as facade which compounds several calls into one.

WCF, Custom Membership Provider and HttpContext

Ok, Im really going to show my stupidity regarding the ASP.NET security model here but here goes.
I have a WCF web service and I have managed to hack my way around to having it pipe through my custom membership provider.
My membership provider overrides "ValidateUser" in which I attempt to load a user object with data from our SQL server instance. All good so far, I retrieve the creds, load the users object and return true if I don't hit any bumps in the road.
At this point, I would usually stuff the user object (or id) into session or actually just some state bag that's accessible for the lifetime of the request. The problem that I am hitting is that HttpContext is null at this point, even though Im using ASP compatability attributes.
What other options do I have at hand?
Cheers, Chris.
EDIT:
Just to clarify what I want to do. I want to pass user credentials to be authenticated on the server, and once this has happened I would like to keep the the details of the authenticated user somewhere that I can access for the lifetime of the service request only. This would be the equiv of Http.Current.Items?
Is there any object that is instantiated per-request that I can access globally via a static property (i.e. in a similar way to HttpContext.Current)? I assumed that OperationContext was the this, but this is also null?
Can this really be such an uncommon problem? Send creds > retrieve user > stuff user somewhere for access throughout processing the request. Seems pretty common to me, what am I missing?
Cheers, Chris.
Basically, with WCF, the preferred best practice solution is to use per-call activation, e.g. each new request / call gets a new instance of the service class, and all the necessary steps like authentication and authorization are done for each request.
This may sound inefficient, but web apps, and in particular web services, ought to be totally stateless whenever possible. Putting stuff in a "state bag" just calls for problems further down the road - how do you know when to invalidate that cached copy of the credentials? What if the user exists your app but the cookie stays on his machine?
All in all, I would strongly suggest trying to get used to the idea of doing these step each and every time. Yes, it costs a little bit of processing time - but on the other hand, you can save yourself from a lot of grief in terms of state management in an inherently stateless environment - always a kludge, no matter how you look at it....
If you still insist on that kludge, you can turn on an ASP.NET "compabitility" mode for WCF which should give you access to HttpContext - but again: I would strongly recommend against it. The first and most obvious limitation is that this ASP.NET compatibility mode of course only works when hosting your WCF service in IIS - which I would again rather not do in production code myself.
To turn on the ASP.NET compatibility mode, use this setting in web.config:
<system.serviceModel>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
and you need to decorate your service implementation (the class implementing the service contract) with a corresponding attribute:
[AspNetCompatibilityRequirements(RequirementsMode=
AspNetCompatibilityRequirementsMode.Allowed)]
class YourService : IYourService
The AspNetCompatibilityRequirementsMode can be NotAllowed, Allowed or Required.
For more information and a more thorough explanation, see Wenlong Dong's blog post on ASP.NET Compatibility Mode