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
Related
My use-case:
I already have a working ASP.NET application
I would like to implement a new Web Service as part of that application
I am supposed to use a WCF service (*.svc), not an ASP.NET web service (*.asmx)
The service needs to have one operation, let’s call it GetInterface(), which returns instance of an interface. This instance must reside on the server, not be serialized to the client; methods called on that interface must execute on the server.
Here’s what I tried (please tell me where I went wrong):
For the purpose of testing this, I created a new ASP.NET Web Application project called ServiceSide.
Within that project, I added a WCF Service using “Add → New Item”. I called it MainService. This created both a MainService class as well as an IMainService interface.
Now I created a new Class library project called ServiceWorkLibrary to contain only the interface declaration that is to be shared between the client and server, nothing else:
[ServiceContract]
public interface IWorkInterface
{
[OperationContract]
int GetInt();
}
Back in ServiceSide, I replaced the default DoWork() method in the IMainService interface as well as its implementation in the MainService class, and I also added a simple implementation for the shared IWorkInterface. They now look like this:
[ServiceContract]
public interface IMainService
{
[OperationContract]
IWorkInterface GetInterface();
}
public class MainService : IMainService
{
public IWorkInterface GetInterface()
{
return new WorkInterfaceImpl();
}
}
public class WorkInterfaceImpl : MarshalByRefObject, IWorkInterface
{
public int GetInt() { return 47; }
}
Now running this application “works” in the sense that it gives me the default web-service page in the browser which says:
You have created a service.
To test this service, you will need to create a client and use it to
call the service. You can do this using the svcutil.exe tool from the
command line with the following syntax:
svcutil.exe http://localhost:59958/MainService.svc?wsdl
This will generate a configuration file and a code file that contains
the client class. Add the two files to your client application and use
the generated client class to call the Service. For example:
So on to the client then. In a separate Visual Studio, I created a new Console Application project called ClientSide with a new solution. I added the ServiceWorkLibrary project and added the reference to it from ClientSide.
Then I ran the above svcutil.exe call. This generated a MainService.cs and an output.config, which I added to the ClientSide project.
Finally, I added the following code to the Main method:
using (var client = new MainServiceClient())
{
var workInterface = client.GetInterface();
Console.WriteLine(workInterface.GetType().FullName);
}
This already fails with a cryptic exception in the constructor call. I managed to fix this by renaming output.config to App.config.
I notice that the return type of GetInterface() is object instead of IWorkInterface. Anyone know why? But let’s move on...
Now when I run this, I get a CommunicationException when calling GetInterface():
The underlying connection was closed: The connection was closed unexpectedly.
How do I fix this so that I get the IWorkInterface transparent proxy that I expect?
Things I’ve tried
I tried adding [KnownType(typeof(WorkInterfaceImpl))] to the declaration of WorkInterfaceImpl. If I do this, I get a different exception in the same place. It is now a NetDispatcherFaultException with the message:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:GetInterfaceResult. The InnerException message was 'Error in line 1 position 491. Element 'http://tempuri.org/:GetInterfaceResult' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/ServiceSide:WorkInterfaceImpl'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'WorkInterfaceImpl' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
The InnerException mentioned is a SerializationException with the message:
Error in line 1 position 491. Element 'http://tempuri.org/:GetInterfaceResult' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/ServiceSide:WorkInterfaceImpl'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'WorkInterfaceImpl' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.
Notice how this seems to indicate that the system is trying to serialize the type. It is not supposed to do that. It is supposed to generate a transparent proxy instead. How do I tell it to stop trying to serialize it?
I tried adding an attribute, [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)], to the WorkInterfaceImpl class. No effect.
I tried changing the attribute [ServiceContract] on the IWorkInterface interface (declared in the shared library ServiceWorkLibrary) to [ServiceContract(SessionMode = SessionMode.Required)]. Also no effect.
I also tried adding the following magic system.diagnostics element to the Web.config in ServerSide:
<system.diagnostics>
<!-- This logging is great when WCF does not work. -->
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
This does generate the c:\traces.svclog file as promised, but I’m not sure I can make any sense of its contents. I’ve posted the generated file to pastebin here. You can view this information in a more friendly UI by using svctraceviewer.exe. I did that, but frankly, all that stuff doesn’t tell me anything...
What am I doing wrong?
The use-case I am describing is not directly supported by WCF.
The accepted work-around is to return an instance of EndpointAddress10 which points to the service for the “other” interface. The client must then manually create a Channel to access the remote object. WCF doesn’t properly encapsulate this process.
An example that demonstrates this is linked to from the MSDN article “From .NET Remoting to the Windows Communication Foundation (WCF)” (find the text that says “Click here to download the code sample for this article”). This example code demonstrates both .NET Remoting as well as WCF. It defines an interface that looks like this:
[ServiceContract]
public interface IRemoteFactory
{
IMySessionBoundObject GetInstance();
[OperationContract]
EndpointAddress10 GetInstanceAddress();
}
Notice that the interface-returning method is not part of the contract, only the one that returns an EndpointAddress10 is marked with [OperationContract]. The example calls the first method via Remoting, where it correctly creates a remote proxy as one would expect — but when using WCF it resorts to the second method and then instantiates a separate ChannelFactory with the new endpoint address to access the new object.
What is MainServiceClient()? It is the class marshaling the client messages to the server.
You should take a look at a related SO post on returning interfaces as parameters in WCF. ServiceKnownTypeAttribute may be helpful.
Sessions may also be what you're looking for MarshalByRef as it relates to .NET Remoting behaviors.
Another approach (as mentioned on MSDN Forums) is to return the EndpointAddress of the service interface instead of the interface itself.
WCF does serialize everything - regardless of the binding. The best approach you should take if you need to communicate with the service on the same system is to use IPC transport binding (net.pipe).
What you are trying to do is a direct violation of the SOA Tenet: "Services share schema and contract, not class". What this means it that you don't actually pass implementation code from the service to its consumers, just the return values that are specified in the contract itself.
The main focus of WCF and SOA in general is interoperability, meaning services should be accessible to clients of any platform. How would a Java or C++ consumer be able to use this service you are designing? Short answer is that it couldn't, which is why you will find it difficult if not impossible to serialize this code over messaging standards like SOAP.
A more appropriate way to structure this code would be to host each implementation of IWorkerInterface as its own service (it has been defined as a service contract, after all), and expose each service on a different endpoint. Instead of MainService behaving as remote factory for proxies to an IWorkerInterface, it could act a as an endpoint factory to the different services you have set up. Endpoint metadata could easily be serialized and provided to the client by IMainService. The client could then take that metadata and construct a proxy to the remote implementation, either through some custom IServiceProxy implementation, or even through the objects already provided to you by WCF (such as the ChannelFactory).
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!
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.
I'm writing what I'm referring to as a POJ (Plain Old JSON) WCF web service - one that takes and emits standard JSON with none of the crap that ASP.NET Ajax likes to add to it.
It seems that there are three steps to accomplish this:
Change "enableWebScript" to "webHttp" in the endpoint's tag
Decorate the method with [WebInvoke(ResponseFormat = WebMessageFormat.Json)]
Add an incantation of [AspNetCompatibilityRequirements(RequirementsMode
= AspNetCompatibilityRequirementsMode.Allowed)] to the service contract
This is all working OK for me - I can pass in and am being returned nice plain JSON.
If I remove the WebInvoke attribute, then I get XML returned instead, so it is certainly doing what it is supposed to do. But it strikes me as odd that the option to specify JSON output appears here and not in the configuration file. Say I wanted to expose my method as an XML endpoint too - how would I do this? Currently the only way I can see would be to have a second method that does exactly the same thing but does not have WebMethodFormat.Json specified. Then rinse and repeat for every method in my service? Yuck.
Specifying that the output should be serialized to JSON in the attribute seems to be completely contrary to the philosophy of WCF, where the service is implemented is a transport and encoding agnostic manner, leaving the nasty details of how the data will be moved around to the configuration file.
Is there a better way of doing what I want to do? Or are we stuck with this awkward attribute? Or do I not understand WCF deeply enough?
I haven't fully tested this out yet, BUT, I took a look at WebMessageFormat in reflector and where it was used in code.
There is a attribute of the webHttp element called defaultOutgoingResponseFormat that can be set to "Json" or "Xml".
<behaviors>
<endpointBehaviors>
<behavior name="ServicesJSONEndpointBehavior">
<webHttp defaultOutgoingResponseFormat="Json"/>
</behavior>
</behaviors>
I've run into the same issue and typically crufted work-arounds after searching online without much info.
I'll give it a shot with multiple configured endpointBehaviors and report back.
UPDATE 6/5/2011
FYI -- I've ditched vanilla WCF with all its hair-pulling scenarios like this that should be simple, in favor of ServiceStack ( http://servicestack.net/ ). If you're looking to put together a standard REST style / document-oriented service over HTTP that out-of-the-box supports JSON / XML / CSV (and in the future protocol buffers) and that allows you to put together clean MVC-style routes with ease, give ServiceStack a hard look. There are a number of things that ServiceStack will handle rather easily and cleanly that always turn out to be a major PITA due to some wonky configuration issue or similar in standard WCF. ServiceStack uses it's own JSON serializer, which as an added bonus, outperforms DataContractJsonSerializer and JSON.NET as Demis mentions below.
I am working on a project that is using NetTcp bindings for talking to some WCF services. When first starting out we took a bad practice example from another application that made WCF calls by using the following:
EntityObject sample = new ServiceProxy().GetEntity();
That worked great until we realized WCF was holding onto the connections even though the aspx page had been sent to the client (which I naively assumed would clean up any connections). While the connections were held on causing things to eventually slow down, ELMAH logged any errors and sent us full stack traces. To resolve the performance issues we changed to this:
using (ServiceProxy proxy = new ServiceProxy())
{
sample = proxy.GetEntity();
}
This made performance rock comparatively. The downside to this method is whenever an error is received on the proxy the only thing ELMAH can catch is that the channel is now faulted. We then have to dig through logs (the WCF ones setup with sharedListeners in ) to figure out what happened and if it's a serialization error the odds of actually find it become much lower, despite the listeners being setup on both client and server. I've explored the IErrorHandler interface and am going to add support for it to our services, but I was wondering if there are other ways to get detailed errors out of WCF instead of it just saying it faulted with no real information as to why it faulted. This would be especially beneficial if it dies on serializing the object that it could tell us WHY it couldn't serialize.
I think if you call Close() explicitly on the proxy, and put that in a try-catch, you'll get what you want.
See especially this sample:
http://msdn.microsoft.com/en-us/library/aa355056.aspx
Well, you can tell the WCF servive to send back more information than just "something bad happened" by using the serviceDebug behavior.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ExceptionDetails">
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
This is OK as long as it's a dev/test environment, or an in-house app. But really, service error should be caught (and logged) on the server side - you're on the right path with the IErrorHandler interface.
The client needs to handle client-side exceptions, like TimeoutException and CommunicationException to deal with security exceptions or networks going down and such. Just standard .NET exception handling, really.
Also, the using() is a good idea in general - but not necessarily here, since you could encounter an exception when the ServiceProxy is being disposed of (at the end of the using() {} block), and that won't be caught in this case. You might just need to use a try {...} catch {...} finally {...} block for your service proxies instead.
Marc