I have a WCF service and methods are exposed as below:
public interface IService
{
[OperationContract]
bool Read();
[OperationContract]
bool Write();
}
public class MyService : IService
{
//Constructor
MyService()
{
//Initialization
}
public bool Read()
{
//Definition
}
public bool Write()
{
//Definition
}
}
I have a desktop based application that consumes the Web service through URL.
This web service can be deployed at multiple location so user can connect to any web service by choosing a url from the combo box.
In the client application I create a Service client dynamically as shown below:
ServiceReference1.DXMyServiceClient _client = null;
_client = new DXMyServiceClient ();
_client.Endpoint.Address = new System.ServiceModel.EndpointAddress(url);
Questions
While debugging I notice whenever I call any methods of web service each time the constructor of MyService is invoked ( if I am connected to the same service).
like for example when I do:
_client.Read();//MyService () constructor is called
_client.Write();//MyService () constructor is called
The problem is I have to do all the initialization again.. like if I connecting to the database then I have to again build the connection string and all stuff..
Is this the natural behavior or I am doing something wrong?
Secondly,
I want to validate user for the valid url ( of web service ). If it is connecting to the valid url or not.. I am doing that through Ping command..
What is the best approach for that!!
Questions While debugging I notice whenever I call any methods
of web service each time the constructor of MyService is invoked
(if I am connected to the same service).
The problem is I have to do all the initialization again..
like if I connecting to the database then I have to again
build the connection string and all stuff..
Yes, that's the default behavior, and the recommended behavior. You should NOT rely on any state on your service side! That is generally not a good idea and can lead to a multitude of problems.
In its recommended "per-call" mode, a WCF service has a ServiceHost() class instance running, which will listen for incoming requests / messages. Each time a request comes in, a new, fresh instance of the service class (that implements your service contract) is constructed to handle the request - just like each time you hit a URL in ASP.NET, your page class is instantiated to handle the request.
Yes, of course - this means you should keep your service classes simple and lean and not do a lot of initialization / state management. Anything that needs to be persisted between service calls should be put in a persistence store, like a database, anyway.
You should look at the ServiceBehaviorAttribute class and it's InstanceContextMode property. It controls the lifetime of your service object.
The problem is I have to do all the
initialization again.. like if I
connecting to the database then I have
to again build the connection string
and all stuff..
Is this the natural behavior or I am
doing something wrong?
By default InstanceContextMode is set to PerSession and ConcurrencyMode is set to Single. However, if you don't use session, basically every time you call service new instance is created. This is desired behavior because it is considered more scalable. If it is a problem for you, you should implement session between subsequent calls then for every session you will get one instance of your service.
Here is a guide how to do that: Using Sessions.
Related
I am new to WCF and am interested what is the best practice to call a service method. The application will consist in a bunch of forms and I would like to know if it's better to declare a global client instance for each form and then just call the methods when needed. Or is it better to instantiate the client proxy before each method call and close it right after.
I believe creating a global var of client for each form will do for you, no need to instantiate service each time before calling the service method.
public MyService ser {get; set;}
Inside class constructor.
ser = new MyService();
The most simple and safest way is constructing client proxy every time you use it.
The drawback of this approach is loosing perfomance, but depending on your binding (http, net.tcp, etc) and service mode (PerCall, Statefull, Singleton) you will not notice the difference (see this answer WCF Proxy Pooling - Is it worth it?).
If you create a proxy on the form level, when this proxy is in the faulted state (because of the connection problems), you won't be able to reuse it and will have to reopen form.
I'm going to be creating a service that needs to make a call to a hosted WCF service halfway around the world. This isn't that big of a deal since the number of transactions that will be made is relatively low. However, I need to pass in an instance of a class that will possibly be defined in the WCF to the necessary WCF function.
So my question is, will that instance of the class exist on my server? Or will I be contacting the host server every time I attempt to set a variable in the object?
EXAMPLE:`
public class Dog
{
public string noise;
public int numLegs;
}
public class doSomething
{
public string makeNoise(Dog x)
{
return x.noise;
}
}
`
All of those are defined in the WCF. So when I create an instance of class Dog locally, will that instance exist on my side or the server hosting the WCF service? If I'm setting 1000 instances of Dog, the latency will definitely build up. Whereas if I DON'T have to contact the server every time I make a change to my instance of Dog, then the only time I have to worry about latency is when I pass it into doSomething.makeNoise.
The host creates a new instance of the service class for each request, if you're using the default per-call instantiation method (which is the recommended way).
So either this is the IIS server which hosting your WCF service that creates an instance of your service class, or it is the ServiceHost instance that you've created inside your own self-hosting setup (a console app, a Windows service etc.).
The service class instance is used to handle your request - execute the appropriate method on the service class, send back any results - and then it's disposed again.
There's also the per-session mode in which case (assuming the binding you've chosen support sessions) your first call will create a service-class instance, and then your subsequent calls will go to the same, already created instance (until timeouts come into play etc.).
And there's also the singleton mode, where you have a single instance of the service class that handles all requests - this is however rather tricky to get right in terms of programming, and "challenged" in terms of scalability and performance
You will need to host your WCF service on a public available server (for example IIS). Successful hosting will provide you with a link for the svc file. Clicking on that will give you a link ending in singleWsdl. You need to copy that link. On your client side, the one that requires a reference to the WCF, you will need to Add Service Reference and pass that link. This will generate proxy code with Client objects that you can use to access your WCF ServiceOperation methods.
At a minimum you should have three projects. A website project to host the actual site. A WCF project to host your services. And finally a shared project, which should contain the classes you are concerned with (the models).
Both the website and wcf projects should reference the shared project, this way they both know how the models look.
The wcf project should return serialzed models as json objects, which I usually do by referencing Newtonsoft.Json.
Your website project should expect this json, and deserialize them, also using Newtonsoft.Json. This is why your class (model) should exist in the shared project, so you can use the same class on both sides of your service call.
Due to network architecture of our software, our application servers cannot connect directly to the web service of our customer. Because of this we have an integration server between the application servers and customer's servers. This integration server hosts a proxy web service. The problem is that the necessary credentials and some other additional information needs to be passed from the database at our application server to our proxy web service at the integration server.
I wouldn't want to pollute the API and pass the object containing credentials and additional information on each web service request. Additionally we have multiple integration servers which can be shut down at will so I cannot just initialize the web service with credentials and other information in a separate method because the subsequent web service requests might be passed to another integration server.
Is there a way to add some kind of SoapExtension which could be used to pass the information to my web service instance on each method? If not, is there something else I could do besides adding an argument to each web method and use that to pass the information?
The answer was actually quite obvious.
Firstly I need to create a class which is derived from SoapHeader. This class is used to store all credentials and other additional information. For easier explaining, let's give this class a name CredentialContainer.
In the actual web service class we need to add a new public property of type CredentialContainer. The property in this example is named Container.
Lastly, we have to add new attribute called SoapHeader to each method with WebMethod attribute. This handles transferring the information passed in the header of SOAP message to our CredentialContainer instance. Because new web service instance is created for each web service request, there are no risk even with multiple concurrent web service requests.
Here's the example code:
[WebService]
public class ExampleWebService
{
public CredentialContainer Container { get; set; }
[WebMethod]
[SoapHeader("Container")]
public void PerformSomething(string value)
{
var actualWebServiceClient = new MyWebServiceClient(Container.Url, ...);
actualWebServiceClient.SendValue(value);
}
}
public class CredentialContainer : SoapHeader
{
public string Url { get; set; }
...
}
I have a self hosted WCF service that I am using in a silverlight application. I am trying to store a list of user guids in an IDictionary object. Each time a user hits the service, it updates the users datetime so I can keep track of which users have active "sessions". The problem is, every time I am hitting the service, the list is empty. It appears to be dropping the values on each soap request?
Can you store information in a self hosted service that will be available across multiple service requests?
Thanks in advance!
It's on a per instance basis. I.e session-less by default.
Have a look at this
When a service contract sets the
System.ServiceModel.ServiceContractAttribute.SessionMode property to
System.ServiceModel.SessionMode.Required, that contract is saying that
all calls (that is, the underlying message exchanges that support the
calls) must be part of the same conversation.
If you need to store things in between requests you will need to create either a static dictionary with the appropriate locking to store these requests as they come in, or store this info in a database (or other external store) and check to see if it exists there in each method call. The reason for this is that the service class is instantiated on every client request.
Since you are already updating the users datetime when a user hits the service it would be better do a lookup to see if this is an active user or not by comparing to the datetime field. This has the advantage of being accurate on every call (the dictionary could get out of sync with the db if the service is restarted). Databases already have mechanisms in place to deal with concurrency, so rather than rolling your own locking solution around a singleton object you can push the complexity to the data store.
If the second solution is not fast enough (and you have profiled the app and determined it's the bottleneck), then the other option is to use some kind of cache solution in front of the db so that data can first be checked in memory before going to the db. This cache object would need to be static like the dictionary and has the same pitfalls around locking as any other multi-threaded application.
EDIT: If this hosted WCF service is being used as session storage for the users of the silverlight application and the data is not being stored in an external data store, then you better be sure that tracking if they are active is not mission critical. This data cannot be guaranteed to be correct as described.
Based on the accepted answer if your service faults and needs to be rebooted (since this is self hosted it is advised that you monitor the faulted event) you have to dispose of the service host and instantiate a new one. The only way the Guid data can be kept is if it is rebound to the service in between restarts (assuming the host app itself isn't restarted which is a different issue).
private Dictionary<Guid,string> _session;
Service service = new Service(_session);
_serviceHost = new ServiceHost(service, GetUriMethodInHostApp());
Better would be to store this externally and do a lookup as #marc_s suggests. Then this complexity goes away.
You need to change the InstanceContextMode. You can do so by adding the following compiler directive to your WCF class:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
This will run the WCF service as a singleton of sorts. See more on WCF Instance Context Mode
And then you should construct your service host with your singleton object. Here's code from a working example where I'm doing something similar:
private ServiceHost serviceHost;
if (serviceHost != null)
serviceHost.Close();
if (log.IsInfoEnabled)
log.Info("Starting WCF service host for endpoint: " + ConfiguredWCFEndpoint);
// Create our service instance, and add create a new service host from it
ServiceLayer.TagWCFService service = new ServiceLayer.TagWCFService(ApplicationName,
ApplicationDescription,
SiteId,
ConfiguredUpdateRateMilliseconds);
serviceHost = new ServiceHost(service, new Uri(ConfiguredWCFEndpoint));
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
As others have politely noted, this can have "consequences" if you're not familiar with how it works or if it's not a good fit for your particular application.
If you don't what to involve locking and thread-safe specific code, you can use a NoSQL database to store your session data, something like MongoDB or RavenDB
Like #marc_s, I think that using the Singleton mode is a risky thing, you have to be very careful in making your own thread-safe session mechanism.
I want to do something just after my WCF service started. How can do it?
In fact,I should update some variable of my service every 10 minutes. So I put my update code in a thread. But I dont know how start this thread when service started (Is there anything liked Form_Load event in WCF services?)
There is typically no parts of your WCF service that is "just hanging around" in memory ready to do something.... WCF is NOT ASP.NET !
The default setup when hosting in IIS is this:
IIS listens on a specific port/URL for a request - there's not a single trace of your WCF service anywhere in memory
when a first request comes in, IIS will spin up a ServiceHost - a class that can "host" a service
this service host will then look at the request has come in and depending on the target URL, it will decide which service class to instantiate to handle this request. The service class (your service implementation) is then created and the appropriate method on that service class is called and executed, and once that's completed, the service class is disposed
So basically, there are two points where you can hook into:
you could create your own custom ServiceHost class that will do something when it gets instantiated
you can add some "initialization" code to each of your service class methods to handle your needs
It's difficult to keep a thread running on a server. As soon as the last session terminates the application shuts down. Some hosting providers also recycle the app pool on a schedule which kills any chance of keeping a thread running.
That aside, WCF Services don't actually run. They act like web pages triggered by a request. The sensible place to add init code would be in your Application_Start in Global.asax. This would get called once when the application starts (the first request is made).
If you would rather do something on each request to your services, you could hook the Application_BeginRequest event also in Global.asax.
You can create an instanced service, which will call the constructor upon the start of your service:
[ServiceContract]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class InstanceService
{
private int _intValue;
public InstanceService()
{
_intValue = 456;
}
[OperationContract]
public int GetData()
{
return _intValue;
}
}
Invoking GetData() on this service will return an integer with a value of 456.
This can be achieved if you are able to control how to host this. If you can, host your WCF service as a Windows service or an ad hoc executable. Then you can achieve what you want with ease. If you are bound to IIS hosting you must do as others have suggested and handle it per request.
Read up on self hosting wcf if IIS is not required.