Access Application global variable from WCF that runs asynchronously - c#

I am trying to access global.asax application variable from WCF, that's my goal at least. I've tried many type of solutions, but the one that I am trying now is using static variables.
I've created a StaticVariable.cs class like so:
public static class StaticVariables
{
private static string _Key = "name1";
public static Object someInfo
{
get
{
return HttpContext.Current.Application[_Key];
}
}
}
The Application["name1"] is initialized in the global.asax.cs. I can read it when I access my webservice but not in my WCF service.
In my WCF I call the StaticVariables someInfo to retrieve the data, but I get:
System.Web.HttpContext.Current is null error
My WCF is running asynchronously and its called from within a webservice using Task<int>.Factory.FromAsync. So I assume that the problem is that the WCF runs not on the main thread, but I am not sure.
So it seems that the Static class doesn't work in my case and I wanted to know how to solve this. Thanks

Why don't you simply use static variables ?
HttpContext is dependent on ASP.NET pipeline. In a host-agnostic model (OWIN or self-hosted) you don't have access to it.
Application storage in HttpApplicationState is only useful if you need to access the current HttpContext. If it's not necessary, you should simply use static properties.
Moreover, HttpApplicationState was initially created for backward compatibility with classic ASP.
public static class StaticVariables
{
public static object SomeInfo { get; set; }
}
See also Singleton and HttpApplicationState and http://forums.asp.net/t/1574797.aspx

Related

How to share a property between multiple WCF services installed on a local machine?

I have a Windows service hosting multiple WCF services. All of it running on a local machine (using NamePipe).
Is there a simple way to have these WCF services share a property? (I would rather not have them sharing a file).
I need this as each session instantiated within each WCF service will be getting a hold on a given hardware and the other WCF services need to know what is still available in order to be able to instantiate another session.
Each WCF service implements a different protocol, which is why I did not merge the lot. There will be one proxy for each host.
I don't know of a super simple way of getting service instances to share a property, but you could create a custom host that derives from ServiceHost and have it implement a particular interface, say something like:
public interface ISharedStateContainer
{
SharedState State { get; set; }
}
This interface would have to be known your services. Then, in your windows service project, you could make a custom service host:
public class CustomServiceHost: ServiceHost, ISharedStateContainer
{
SharedState state;
public SharedState State{ get{ return state; } set{ state=value; } }
}
...and then when the windows service creates the wcf service host instances, it could inject the shared state:
var sharedState = new SharedState();
myServiceHost = new CustomServiceHost( typeof( MyService ) );
((ISharedStateContainer) myServiceHost).State = sharedState;
myOtherHost = new CustomServiceHost( typeof( OtherService ) );
((ISharedStateContainer) myOtherHost).State = sharedState;
myServiceHost.Open();
myOtherHost.Open();
...and then, in a running instance of a service, you could get to shared state like this:
var sharedState = ((ISharedStateContainer)OperationContext.Current.Host).State
Where I've got SharedState, you could make it any type you want...but making it a reference type that itself has properties means you can use it to share as many properties as you need. Note that with any shared state, you'll have race conditions to protect against.
I've done a windows service the same way (multiple different wcf service types)...and this is more-or-less how they share state.
EDIT:
I don't know why I didn't think about this sooner, but another nice way to share state is using a singleton. This is probably more straightforward than the earlier approach. I have this pattern going on, too...for a somewhat different reason, but it would serve for shared state, too:
public class SharedState
{
//--> singleton instance...
static readonly SharedState current;
//--> use static initializer to create the current instance...
static SharedState( )
{
current = new SharedState();
}
//--> hide ctor...
private SharedState(){}
public static SharedState Current
{
get { return current; }
}
//--> all your shared state instance methods and properties go here...
public string SomeString
{
get
{
return //...
}
}
}
...and then you can get to this object from anywhere in your service, even from code not running in the context of a client operation. I use this for long running background task that the service needs to perform periodically, but shared properties are super easy:
var someValue = SharedState.Current.SomeString;

State in ApiController

I need to provide an api to a long running windows service which does a bunch of processing and retains a memory of that history. An api is required to provide status on current activity levels of the system (records processed, records waiting to be processed, etc).
I was wanting to use a self-hosted Owin ApiController to provide a nice interface to the system. However, the ApiController is completely stateless and there is no method (after searching dozens of IoC posts) for injecting an already active instance into the controller.
Is there a way to provide a class instance to an ApiController?
I don't think you can inject an old instance of the controller, because you get a new instance every time you perform a request.
However you can create a singleton object with a collection inside, and you can inject it into the controller constructor and use in every request.
You can also use some sort of persistence such as DB, that you can run on your device.
Here is an example for a singleton class:
using System;
public class Singleton
{
public Dictionary<string,object> State {get; private set;}
private static Singleton instance;
private Singleton() {
State = new Dictionary<string,object>();
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
Even though you can get Session state in web api controller, it is going to be questionable solution, instead, I would recommend going the following way:
include Hangfire as dependancy and use it for long running tasks
Use signal-r to to push state of background task
return JobID from your API method and use it on the client to subscribe to signal-r hub

managing static data within WCF

I am working within a solution that has a static logging object in a library that is shared among the projects. This is how it is structured:
public class AppLog
{
private static string _logFile;
private static string _appName;
public static string AppName
{
get { return _appName; }
set
{
_appName = value;
InitLogFilePath(); // initializes _logFile according to _appName
}
}
public static Write(string msg)
{
// writes to _logFile
}
}
It works fine for the various Windows apps and Windows services: They can initialize AppLog.AppName upon startup and AppLog.Write can be called throughout the code. Shared modules write to a file named according to the initialization of AppName.
The problem I have is using this within WCF web services. The web services are configured for InstanceContextMode.PerCall. AppLog.AppName is being initialized according to ServiceHostBase.Description.Name. But since multiple web services run within the same AppDomain this static data is shared. So one ws call sets AppLog.AppName and it is changed by the next call, which may have a different ServiceHostBase.Description.Name.
How can this be restructured so that AppLog.Write can still be used throughout the projects in my solution but handle the naming differently for each web service?
If could tell whether the code is running within a web service, and if I could retrieve the ServiceHostBase.Description of the service, then I could maintain a lookup for the appropriate file name. But I have not yet found a way to do this.
Given the way your logging is structured there is not a good solution.
Most logging libraries are structured so that you create an instance of the logger, pass the instance any application specific data (like AppName), and then store that instance in a private static member. The static storage is in the application, not the logging library. This avoids the sharing conflict that you have and still only creates a small fixed number of logger instances.
To illustrate the point, here's a standard log4net example from CodeProject log4net tutorial. This code passes the current class name to the instance of the logger.
private static readonly log4net.ILog log = log4net.LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
My suggestion is to look at changing to log4net or any of the other logging packages available on NuGet.
Given your situation, AppName is not where is should be. You need a per-webservice logging facade that hold the AppName and pass the core "Write" logic down to your current AppLog. Then each of the web service has its own LogFacade instance.
class LogFacade
{
public string AppName {get; private set;}
LogFacade(string appName)
{
AppName = appName;
}
public void Write(string msg)
{
AppLog.Write(string.format("[{0}]{1}", AppName, msg));
}
}
Or as ErnieL said, take a look at log4net.

Static Variables in WCF

I have some WCF services. These services run in ASP.NET. I want these services to be able to access a static variable. My problem is, I'm not sure where the appropriate server level storage mechanism is. I don't want to use the database because of speed. But, I want the static variables to stay in memory as long as possible. In fact, I'd like it to stay until I restart my server if it all possible.
Can anyone provide me with any ideas?
You could use static variables in WCF but you must properly synchronize the access to them because they can potentially be accessed from multiple threads concurrently. The values stored in static variables are accessible from everywhere in the AppDomain and remain in memory until the server is restarted.
You could have something like this
public static class StaticVariables
{
private static string _variable1Key = "variable1";
public static Object Variable1
{
get
{
return Application[_variable1Key];
}
set
{
Application[_variable1Key] = value;
}
}
}
The Application collection itself is thread safe but the stuff you add to it might not be; so keep that in mind.
If all the services are in a single ServiceContract and if all the member variables in your service can be shared across all sessions, then you could set the ServiceBehavior to have a single instance.
[ServiceBehavior( InstanceContextMode = InstanceContextMode.Single )]
public class MyService : IMyServiceContract
{
}

Access the current InstanceContext in a WCF UsernamePasswordValidator

I have a WCF service that is using a custom UsernamePasswordValidator. The validator needs to access my entity framework context.
I would like to create one ObjectContext for the entire service call and then destroy/dispose it at the end of the call. So I created a singleton static class that provided this functionality, however, what's happening now is that if two service calls happen concurrently, one of the calls disposes the singleton.
I either keep a local reference to the ObjectContext, in which case the second service to use it sees it as disposed and throws and error, or, I put a wrapper property around the Singleton class wherever I need it and then all my changes get thrown away because I'm getting a new instance of the object if another call has disposed it.
So basically my question is how do I instantiate an ObjectContext per service call?
NOTE: The instance needs to be accesible in both the service code AND the custom UsernamePasswordValidator code.
I can't just do it in the constructor or use a using statement because then the custom UsernamePasswordValidator doesn't have access to it. Is there a way to have a static class per call? It does sound impossible, but what's the way around this? Should I be caching the object in a session?
My service is hosted in IIS.
UPDATE:
So I've nailed this down to storing state in the InstanceContext using an IExtension object. But How do I access the current InstanceContext in a UsernamePasswordValidator?
Ok, so in the end I solved it by using the following static class and relying on ASP.NET to cache the context for me.
I'm not sure if this is the best way to do things, but this allows me to use one ObjectContext per request so I'm not spinning up too many and this also means I don't have to use a lock on the object which would become a nightmare if many users were using the service.
public static class MyContextProvider
{
public static MyModel Context
{
get
{
if (HttpContext.Current.Items["context"].IsNull())
{
HttpContext.Current.Items["context"] = new MyModel();
}
return HttpContext.Current.Items["context"] as MyModel;
}
}
}
Then wherever I need an ObjectContext in the app I just call
var context = MyContextProvider.Context;
You have one instance per call, you also have 1 call per instance.
So it should be very simple, use a using () { } block in the toplevel of your OperationContract method.
Ok, here is the class with thread-safe static method that provides single ObjectContext entity model object for any WCF service call and automatically dispose it at the end of call:
public static class EntityModelProvider
{
private static readonly Dictionary<OperationContext, MyEntityModel> _entityModels = new Dictionary<OperationContext, MyEntityModel>();
public static MyEntityModel GetEntityModel()
{
if (OperationContext.Current == null)
throw new Exception("OperationContext is missing");
lock (_entityModels)
{
if (!_entityModels.ContainsKey(OperationContext.Current))
{
_entityModels[OperationContext.Current] = new MyEntityModel();
OperationContext.Current.OperationCompleted += delegate
{
lock (_entityModels)
{
_entityModels[OperationContext.Current].Dispose();
_entityModels.Remove(OperationContext.Current);
}
};
}
return _entityModels[OperationContext.Current];
}
}
For your service, you can specify a service behaviour which details the instance mode of the service:
[ServiceBehaviour(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService {
ObjectContext context;
}
A cleaner way may be to use the ServiceAuthenticationManager, which is in .NET 4.
http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthenticationmanager.aspx
From the Authenticate method (which you'll override) you can access the Message object and set properties on it. I've not used it in anger, so YMMV :)
EDIT the problem with this approach is that you don't have the Username and Password, so will still need the custom Authentication.
Take a look at the UsernameSecurityTokenAuthenticator...
http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.usernamesecuritytokenauthenticator(v=vs.90).aspx
Further reading from my research:
Answers to this question gives some hints about how to use it:
Custom WCF authentication with System.ServiceModel.ServiceAuthenticationManager?
If you can read (or ignore) the Russian, I found useful hints at:
http://www.sql.ru/forum/actualthread.aspx?tid=799046
This rather good CodeProject article goes further (encryption and compression as well as custom authorization)
http://www.codeproject.com/Articles/165844/WCF-Client-Server-Application-with-Custom-Authenti
Why not pass in the context into your CustomValidator when you assign to the service - store your object context in your validator, and in the overridden validation method new it up if need be. Then you still have access to the object through the Services CutomUserNameValidator ..
Depending on what you are asking :
Create your separate ObjectContext class as a dynamic object - add that as a property to you CustomValidator.
In your custom Validator - you can now check if the object is disposed and create the object again if need be.
Otherwise if this is not what you are after - just store the Context in the validator - you still have access on server side.
The code here is just generalized idea - I am just posting it as a frame of reference so you can have an idea of what I talking about.
public DynamicObjectContextObjectClass
{
ObjectContext internalObjectContext;
}
public class ServiceUserNamePasswordValidator : UserNamePasswordValidator
{
public DynamicObjectContextObjectClass dynamiccontext;
public override void Validate(string userName, string password)
{
if(dynamiccontext.internalObjectContext.isdisposed)
{
dynamiccontext.internalObjectContext = new Context;
}
try
{
if (string.IsNullOrEmpty(userName) || password == null)
{
//throw new ArgumentNullException();
throw new FaultException("Username cannot be null or empty; Password cannot be null and should not be empty");
}
}
}
}

Categories