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.
Related
I have a (classic) cloud service that needs to create an expensive object that I want to be reused in subsequent requests. It takes a long time to create so creating it each time slows down the requests unacceptably.
public class MyService : IHttpHandler
{
public static ExpensiveObject MyObject;
public void ProcessRequest(HttpContext context)
{
if (MyObject == null)
MyObject = new ExpensiveObject(); // very time consuming operation
// do stuff with MyObject
}
}
(I realise the lack of consideration for multiple concurrent requests running, please disregard that) When I post two requests, one after the other, it creates a new MyObject each time. How can I ensure that it reuses the same object created for each request?
Setting IsReusable to return true in the MyService seemingly makes no difference.
It looks like you need to move out the shared object from HttpHandler to separate hosted service, for example, Azure App Service, Azure WebJob (it isn't suited for all scenarios of using), etc.
Azure App Service scenario: web app communicates with App Service by HTTP (see HttpClient). Azure App Service has the configuration option Always On that keep the app loaded even when there's no traffic.
If you deal with a long-running operation (although you wrote that problem is long-initialization) then make sense to look at the standard REST-pattern resolving such problems - Polling.
Maybe this link be useful for you: Common causes of Cloud Service roles recycling.
If you’re running inside IIS you cant. The application pool is at work. Additionally, multiple requests typically won’t cross paths in-process.
Your typical options include the following. It will only create one expensive service per thread:
IoC registering the service’s lifecycle per thread (or request scope).
a singleton (app pool already in use)
-Best of luck!
To achieve this easily (without dealing with arcane Azure crap) I just made a separate executable that hosts the ExpensiveObject in a Nancy localhost server (started in a startup script).
In my case this has no significant drawbacks as I just need to request the object to consume a string and return another string. This might not be the right solution for everyone however.
My project is a consumer for a 3rd party web service (old school web service vs. WCF service), and it has two versions, the "sandbox" (staging), and prod services. The APIs on these services are almost identical, and I am looking for a way to cleanly switch between the two versions, preferably without using conditional compilation.
I instinctively rushed off and extracted an interface from the client generated by Visual Studio's "Add web reference", i.e. AgentImport but that class is not partial, so I can't make it derive from the interface, or from any other superclass. I already have the creation of AgentImport instances nicely encapsulated in an abstract base for all my clients of AgentImport, but without using more risky compiler directives, how can I switch between v1 and v2 of AgentImport?
Some code:
using Clients.PrivateProperty.AgencyServicesApiService;
namespace Client.PrivateProperty
{
public abstract class PrivPropFacilityBase
{
protected static AgentImport Client;
protected PrivPropFacilityBase()
{
Client = new AgentImport();
Client.Timeout = 10000;
}
protected virtual AgentImport GetClient()
{
return new AgentImport();
}
}
}
I have tried adding service references instead of web references, as advised in comments below, to at least get access to partial classes, but when I add the first service reference, for the production service, and extract an interface from the auto-generated SOAP client, i.e. IAsapiClient, that interface references objects declared in other auto-generated classes, in the same namespace as the client, e.g. SecurityToken:
void UpdateUniqueAgentID(string PrivatePropertyAgentId, string AgentId, AgencyServicesApiService.SecurityToken Token);
If I add the second service reference, for the staging service, that second auto-generated SOAP client references objects in its own namespace, e.g. now it uses AgencyServicesApiSandbox.SecurityToken, so my compiler tells me that it doesn't implement the interface I extracted the first time. I am then left with the messy business of having to extract an new interface for each object that the main interface, IAsapiClient, references, so that this main interface only uses the extracted contracts, not actual class names.
In pursuing the above< I have reached the conclusion that my only feasible, and lowest risk, way forward is to use two client projects, one specifically for the production service, and one for the staging service. Then, at execution time, I only need to worry about dynamically choosing between two well known, i.e. not auto-generated, client objects.
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 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.
I'll be more specific.
Lets say I have a contract defined for my WCF service. And I have two different WCF clients which reference to this service : "ClientA" and "ClientB".
Now , lets say I want to add an operation (method) to my service which only "ClientB" will use , Lets say I added this operation to the contract and "ClientB" updated its reference and we're all happy. Does clientA also need to update it's reference even though it is not using the new operation?
The client only needs to update his reference, if it's going to use the new Operation contract.
Check out this article: Versioning WCF Contracts
No, WCF web references are generated by the IDE very similarly to references to ASMX or other web services, which means that it breaks things down into a method inventory, such that the client calling code operates as though it were invoking a remote API. Therefore, if only new stuff that does not alter the expected existing functionality is added, then old clients do not need to update.