I Have a service that generate a Sudoku Game, the client should be Windows Phone User, I'm making online competition.
Question #1 Is how can I generate the Same Sudoku Game For all Clients (who access the service) in a specific time say in 20 minutes.
I read about this and i try to use the following :
[ServiceBehavior (InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Single)]
but it isn't working properly.
Question # 2 is how to close the service for all clients after specific time.
thanks.
The default behaviour of a WCF service, as you have probably figured out, will create a new instance of the service implementation for every call. This is intentional, as the context may be different depending on the identity of the client. I would recommend not trying to change this behavior.
As Guanxi said, a good approach is to implement a static cache - like a singleton, which re-generates it's self after a timeout of 20 minutes.
Example C# code:
public static class SudokuCache
{
private static Sudoku _game;
private static DateTime _timestamp;
public static Sudoku Game
{
get {
if (_timestamp.AddMinutes(20) < DateTime.Now) {
_game = new Sudoku();
_timestamp = new DateTime.Now;
}
return _game;
}
}
}
public class Sudoku { }
With this approach your service can handle client authentication/identity, keep scores etc and just provide a new game via a call to SudokuCache.Game.
As with anything WCF, make sure you use DataContract/DataMember attributes so you can correctly serialize your Sudoku object.
Answer#1: Generate Sudoko and cache it on server with time-stamp. Then all the request coming in next 20 mins of timestamp, return the cached result. Any request that doesn't satisfy criteria of time will trigger generation and caching of new Sudoku.
Answer#2: just put time check in you service and returning a flag indicating Service unavailable.
Nothing is WCF specific, as in comments, you will have to write the logic.
Related
I have a publisher / subscriber pattern WCF Duplex ServiceHost that is hosted by a Windows Service. The Windows Service receives events from a separate process. OnEvent I would like to force my WCF Host to publish that data to all subscribed clients. Typically if a Client is calling this is straight forward. But when my Service Host needs to do this - I can't get my head around HOW to do that.
I have 2 questions:
1: I do not know how to create a Channel in WCFHost from my Windows Service so that it can use to publish to the Subscribers.
2: I read Creating WCF ChannelFactory so I do know I am creating a DuplexChannelFactory (2 per second ) which might be too much overhead.
Any help examples, hints are greatly appreciated. I am not a WCF expert and currently know more about it than I thought I should have to know in order to use it.
I had read on SO
Can I call a Method in a self hosted wcf host locally?
So then I have created a method inside my WCFHost like so:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
AutomaticSessionShutdown = false,
IncludeExceptionDetailInFaults = true)]
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServerHost<TService> : ServiceHost where TService : class
{
public T GetDuplexClientChannel<T, Cback>(BindingType bindingType, EndpointAddress endPointAddress) where T : class
{
ServiceEndpoint sep = GetContractServiceEndPoint<T>(bindingType, endPointAddress);
lock (_syncRoot)
{
DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(typeof(Cback), sep);
return factory.CreateChannel(endPointAddress);
}
}
}
I get an error of course that there is no InstanceContext because I am constructing using typeof(Cback) ..
"This CreateChannel overload cannot be called on this instance of DuplexChannelFactory, as the DuplexChannelFactory was initialized with a Type and no valid InstanceContext was provided."
So I am not sure how I can go about performing this ?
And for those that say read the error : yes I read the error.
Now how to do that with an InstanceContext that does not exist as OperationContext.Current does not exist at this point as I am calling this method form my Hosting Process into my WCFHost.
So if I could have a nice example of how to do this - even if I must use the code example on the 2nd link (of course implementing the DuplexChannelFactory) I would greatly appreciate it.
EDIT
Basically the windows Service is doing some heavy work monitoring other services, about 2 times a second it then must publish that to "Subscribed" Clients via WCF.
I think you have got very confused about how everything is wired together and are mixing concepts from the client in with the service. You haven't provided much concrete information about your scenario to go on so I'm going to provide a small example and hopefully you will be able to apply the ideas to your problem.
[ServiceContract(CallbackContract=typeof(IMyServiceCallback))]
public interface IMyService
{
[OperationContract]
void Register();
}
public interface IMyServiceCallback
{
[OperationContract]
void ReceiveData(string data);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
static HashSet<IMyServiceCallback> s_allClients = new HashSet<IMyServiceCallback>();
static object s_lockobj = new object();
public void Register()
{
lock(s_lockobj)
{
_allClients.Add(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>());
}
}
public static void SendDataToClients(string data)
{
HashSet<IMyServiceCallback> tempSet;
lock(s_lockobj)
{
tempSet = new HashSet<IMyServiceCallback>(_allClients);
}
foreach(IMyServiceCallback cb in tempSet)
{
try
{
cb.ReceiveData(data);
}
catch(Exception)
{
lock(s_lockobj)
{
_allClients.Remove(cb);
cb.Abort();
cb.Dispose();
}
}
}
}
}
In your OnEvent method, you would call something similar to this inside your event method.
MyService.SendDataToClients(mydata);
This uses static data to store the list of clients. If you wanted to do something like segment your clients for different endpoints, you would need to do something different. There is a potential out of order message and scaling problem with this code if your OnEvent method can be called again while the previous call hasn't completed. For example, if you receive 2 messages, the first being large and the second being small, you could potentially send the second smaller message to clients later in the HashSet iteration order before they have been sent the first message. Also this won't scaled to a large number of clients as you could block timing out on one client holding up messages being sent to other clients. You could use something similar to Task's to dispatch multiple message deliveries. If this needs to scale, I would suggest looking at Reactive Extensions for .Net
I am using NServicebus(version 4.6.3) with SQLTransport in my ASP.net web api project. I have different connectionstrings for the queues for different environments (Dev,QA,etc). My configuration looks like below:
public class BusConfigurator
{
public static IStartableBus Bus { get; private set; }
public static void DisposeBus()
{
if (Bus == null)
return;
Bus.Shutdown();
Bus.Dispose();
Bus = null;
}
public static void InitializeServiceBus(string connectionString)
{
var configure = Configure.With()
.DefineEndpointName("MyEndPoint")
.Log4Net(new DebugAppender { Threshold = Level.Warn })
.UseTransport<SqlServer>(connectionString)
.PurgeOnStartup(false)
.SetDefaultTransactionLevel()
.UnicastBus(); // Error is thrown here on second call
configure.MyCustomSQLServerPersistence();
Bus = configure.CreateBus();
}
public static void StartBus()
{
Bus.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
}
I have a dropdown in the app so that the user can select the environment. Based on the selection, I want to reconfigure the bus. So, I call DisposeBus then pass the connection string to the IntializeServiceBus method followed by the startBus. It works first time but throws error below when it gets called again with different connectionstring:
Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Source=NServiceBus.Core
Line=0
BareMessage=Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Is NServicebus intended to be used/configured this way? (I am guessing probably not) If not then is there a workaround/different approach for this?
In V4 or below, there is no way to do it by normal human means. There is only one Bus per AppDomain. All of the configuration API is static, so if you try, you get exactly the problems you ran into.
By "human means", I mean that it might be possible to do something crazy with spinning up a new AppDomain within your process, setting up a Bus within that, and then tearing it down when you're finished. It might be possible. I haven't tried it. I wouldn't recommend it.
In V5, the configuration API is completely redesigned, is not static, and so this is possible:
var cfg = new BusConfiguration();
// Set up all the settings with the new V5 Configuration API
using (var justOneBus = NServiceBus.Bus.Create(cfg).Start())
{
// Use justOneBus, then it gets disposed when done.
}
That's right. It's disposable. Then you can do it again. In your case you wouldn't want to put it in a using block - you would want to set it up somewhere, and when the dropdown gets switched, call Dispose on the current instance and rebuild it with the new parameters.
Keep in mind, however, that the Bus is still pretty expensive to create. It's definitely still something you want to treat as an application-wide singleton (or singleton-like) instance. You definitely wouldn't want to spin up a separate one per web request.
I have to build a windows service that grabs data from n number of client databases, convert the result set to XLS format and send it to corresponding (client specific) FTP account at client specified interval,
Here's another way of putting it:
Same Windows Service will connect to multiple databases, sends files to different FTP accounts and runs at different intervals based on which client DB it is connected to.
My question is, how should I design it so that it's flexible to handle multiple scenarios and is more configurable.
The basic idea behind this is to minimize the implementation time in future when a new client asks for the same service.
I am considering the following idea where an individual client can be set to a separate worker thread. I know something is terribly wrong with this approach but can't seem to figure out the best way.
Here's the partial code:
private static void Main(string[] args)
{
// Initialize the first worker thread.
NewUserThread newUserThread = new NewUserThread();
// Specify properties of this worker thread.
newUserThread.Name = "New User Check";
newUserThread.Delay = 0;
newUserThread.Interval = 2 * 60 * 1000;
// Initialize the second worker thread.
UserUpdateThread userUpdateThread = new UserUpdateThread();
// Specify properties of this worker thread.
userUpdateThread.Name = "User Update Check";
userUpdateThread.Delay = 30 * 1000;
userUpdateThread.Interval= 5 * 60 * 1000;
// Initialize the first Windows service objects.
WindowsService userCheckService = new WindowsService();
userCheckService.ServiceName = UserCheckServiceName;
// Initialize the second Windows service objects.
WindowsService emailService = new WindowsService();
emailService.ServiceName = EmailServiceName;
// Add services to an array.
ServiceBase[] services = new ServiceBase[]
{
userCheckService,
emailService,
};
// Launch services.
SendFiles("Launching services...");
Run(services, args);
}
internal static void (string message, params object[] args)
{
// Call to DB
// Convert dataset to XLS
// Send to FTP
}
Let me know if I am not making any sense and I am open to explore a completely new approach.
Code sample will help.
Thanks all in advance!
Well i am gonna write the architecting stuff so that the application stays extensible in future.
Pattern Used: Dependency Injection
Make a Interface named IDatabaseSources and implement the interface in the different datasourceclasses
A sample method for your IDatabaseSource interface would be Connect(),FetchData(). When you program the connect method in the implemented classes fetch the connection string from web.config.
public class SQLDataSource:IDatabaseSources { will have all the methods defined in the interface}
public class SQLDataSource2:IDatabaseSources{ will have all the methods defined in the interface}
Make a interface named IFTPSources and implement the interface in the different classes.
A sample method for your IDatabaseSource interface would be Connect(),SendData(). When you program the connect method in the implemented classes fetch the FTP information from web.config.
public class FTPSource1:IFTPSources{ will have all the methods defined in the interface}
public class FTPSource2:IFTPSources{ will have all the methods defined in the interface}
Further these dependency's should be injected in the windows service as per your scheduler
Although if there are 10 FTP destinations then you'll have 10 FTP source class. Yes it increases number of classes but that's what single responsibility principle is plus that way you'll be able to maintain/extend the application.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
WCF Windows Service - Long operations/Callback to calling module
I have a WCF application hosted on windows service. I have to use basicHttpBinding. In the application, I make a long-term analysis of the data, and then turn them into customers.
Is it possible to call WCF creating a thread that will be carried out analysis (Id of this thread will be sent to the client)?
The client should be able to communicate with the theme of using the transmitted ID and, if it receives information that the data is ready, it should be able to be downloaded. This will, in turn, release the thread.
How can I achieve this functionality?
Ok. It works. Client method call creates a thread that even after paying guid runs in the background and saves the result of the operation. How best can store these results? Due to the fact that the service is running Per Call dictionary resets with each calling the service. Declaring static data can be overridden, but I do not think it was a good idea. Any ideas?
namespace WCFRiskService
{
[ServiceContract]
public interface IRiskService
{
// return Thread ID
[OperationContract]
int GetAnalysis(AnalysisId);
[OperationContract]
string GetAnalysisData(int ThreadId);
}
public class Analysis
{
public GenerateAnalysis()
{
Thread.Sleep(20000);
Analysis = "Generated Data";
}
}
public class RiskService : IRiskService
{
// How can I change this, to use non-static objects ?
static string AnalysisData = "";
public string GetAnalysisData(int ThreadId);
{
return AnalysisData;
}
public int GetAnalysis(AnalysisId);
{
Analysis AObject = new Analysis();
AObject.Tree = AnalysisTree;
Thread workerThread = new Thread(AObject.GenerateAnalysis);
int managedThreadId = workerThread.ManagedThreadId;
workerThread.Start();
while (!workerThread.IsAlive) ;
return managedThreadId;
}
}
}
You could create a job Id (Guid) for each job and pass it back to the client. Then in the service, store the job Id on a ConcurrentDictionary<Guid, AnalysisResult> and when the client asks for the results, you return the AnalysisResult that corresponds to the job Id. The client will need to check if the AnalysisResult that is returned by the operation is not null and etc.
Note that polling is not the best approach though.
If you could replace basicHttpBinding with wsDualHttpBinding then have a look at the duplex services that allow both endpoints to send messages. This way the server can send messages to the client anytime it wishes to. You could created a callback interface for progress reporting.
So I've decided to up the performance a bit in my WCF application, and attempt to cache Channels and the ChannelFactory. There's two questions I have about all of this that I need to clear up before I get started.
1) Should the ChannelFactory be implemented as a singleton?
2) I'm kind of unsure about how to cache/reuse individual channels. Do you have any examples of how to do this you can share?
It's probably important to note that my WCF service is being deployed as a stand alone application, with only one endpoint.
EDIT:
Thank you for the responses. I still have a few questions though...
1)I guess I'm confused as to where the caching should occur. I'm delivering a client API that uses this code to another department in our company. Does this caching occur on the client?
2)The client API will be used as part of a Silverlight application, does this change anything? In particular, what caching mechanisms are available in such a scenario?
3)I'm still not clear about the design of the GetChannelFactory method. If I have only one service, should only one ChannelFactory ever be created and cached?
I still haven't implemented any caching feature (because I'm utterly confused about how it should be done!), but here's what I have for the client proxy so far:
namespace MyCompany.MyProject.Proxies
{
static readonly ChannelFactory<IMyService> channelFactory =
new ChannelFactory<IMyService>("IMyService");
public Response DoSomething(Request request)
{
var channel = channelFactory.CreateChannel();
try
{
Response response = channel.DoSomethingWithService(request);
((ICommunicationObject)channel).Close();
return response;
}
catch(Exception exception)
{
((ICommenicationObject)channel).Abort();
}
}
}
Use the ChannelFactory to create an instance of the factory, then cache that instance. You can then create communicatino channels as needed/desired from the cached istance.
Do you have a need for multiple channel factories (i.e.., are there multiple services)? In my experience, that's where you'll see the biggest benefit in performance. Creating a channel is a fairly inexpensive task; it's setting everything up at the start that takes time.
I would not cache individual channels - I'd create them, use them for an operation, and then close them. If you cache them, they may time out and the channel will fault, then you'll have to abort it and create a new one anyway.
Not sure why you'd want to usea singleton to implement ChannelFactory, especially if you're going to create it and cache it, and there's only one endpoint.
I'll post some example code later when I have a bit more time.
UPDATE: Code Examples
Here is an example of how I implemented this for a project at work. I used ChannelFactory<T>, as the application I was developing is an n-tier app with several services, and more will be added. The goal was to have a simple way to create a client once per life of the application, and then create communication channels as needed. The basics of the idea are not mine (I got it from an article on the web), though I modified the implementation for my needs.
I have a static helper class in my application, and within that class I have a dictionary and a method to create communication channels from the channelf factory.
The dictionary is as follows (object is the value as it will contain different channel factories, one for each service). I put "Cache" in the example as sort of a placeholder - replace the syntax with whatever caching mechanism you're using.
public static Dictionary<string, object> OpenChannels
{
get
{
if (Cache["OpenChannels"] == null)
{
Cache["OpenChannels"] = new Dictionary<string, object>();
}
return (Dictionary<string, object>)Cache["OpenChannels"];
}
set
{
Cache["OpenChannels"] = value;
}
}
Next is a method to create a communication channel from the factory instance. The method checks to see if the factory exists first - if it does not, it creates it, puts it in the dictionary and then generates the channel. Otherwise it simply generates a channel from the cached instance of the factory.
public static T GetFactoryChannel<T>(string address)
{
string key = typeof(T.Name);
if (!OpenChannels.ContainsKey(key))
{
ChannelFactory<T> factory = new ChannelFactory<T>();
factory.Endpoint.Address = new EndpointAddress(new System.Uri(address));
factory.Endpoint.Binding = new BasicHttpBinding();
OpenChannels.Add(key, factory);
}
T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel();
((IClientChannel)channel).Open();
return channel;
}
I've stripped this example down some from what I use at work. There's a lot you can do in this method - you can handle multiple bindings, assign credentials for authentication, etc. Its pretty much your one stop shopping center for generating a client.
Finally, when I use it in the application, I generally create a channel, do my business, and close it (or abort it if need be). For example:
IMyServiceContract client;
try
{
client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress");
client.DoSomething();
// This is another helper method that will safely close the channel,
// handling any exceptions that may occurr trying to close.
// Shouldn't be any, but it doesn't hurt.
Helper.CloseChannel(client);
}
catch (Exception ex)
{
// Something went wrong; need to abort the channel
// I also do logging of some sort here
Helper.AbortChannel(client);
}
Hopefully the above examples will give you something to go on. I've been using something similar to this for about a year now in a production environment and it's worked very well. 99% of any problems we've encountered have usually been related to something outside the application (either external clients or data sources not under our direct control).
Let me know if anything isn't clear or you have further questions.
You could always just make your ChannelFactory static for each WCF Contract...
You should be aware that from .Net 3.5 the proxy objects are pooled for performance reasons by the channel factory. Calling the ICommunicationObject.Close() method actually returns the object to the pool in the hope it can be reused.
I would look at the profiler if you want to do some optimisation, if you can prevent just one IO call being made in your code it could far outweigh any optimisation you will make with the channel factory. Don't pick an area to optimise, use the profiler to find where you can target an optimisation. If you have an SQL database for instance, you will probably find some low hanging fruit in your queries that will get you orders of magnitude performance increases if these haven't already been optimised.
Creating the Channel costs the performance so much. actually , WCF already has the cache mechanism for the ChannelFactory if you use the ClientBase in the client instead of the pure ChannelFactory. But the cache will be expired if you make some anditional operations(Please google it for details if you want).
For the ErOx's issue i got another solution i think it is better. see below:
namespace ChannelFactoryCacheDemo
{
public static class ChannelFactoryInitiator
{
private static Hashtable channelFactories = new Hashtable();
public static ChannelFactory Initiate(string endpointName)
{
ChannelFactory channelFactory = null;
if (channelFactories.ContainsKey(endpointName))//already cached, get from the table
{
channelFactory = channelFactories[endpointName] as ChannelFactory;
}
else // not cached, create and cache then
{
channelFactory = new ChannelFactory(endpointName);
lock (channelFactories.SyncRoot)
{
channelFactories[endpointName] = channelFactory;
}
}
return channelFactory;
}
}
class AppWhereUseTheChannel
{
static void Main(string[] args)
{
ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint");
}
}
interface IMyContract { }
}
you can customize the logic and the parameters of the Initiate method yourself if you got another requirement. but this initiator class is not limited only one endpoint. it is powerful for all of the endpoint in your application. hopefully. it works well for you. BTW. this solution is not from me. i got this from a book.