Share HttpContext code between web and non-web application - asp.net

I've got a VB.NET module that reads from a resource file to display text in the correct language. Here's my problem - this code is shared between a web application and a non-web application, In the web application, I'm using System.Web.HttpContext to determine the user's preferred language, but now my Windows app won't even compile, because it says HttpContext isn't defined (I've already tried adding an imports for the full namespace - no dice).
I would love to use some kind of try/catch block if I can't otherwise work around it, but that doesn't change that the windows app won't compile with a reference to HttpContext in it. Without moving this chunk of code into a new file and including it only in the web application (I don't own that app, so I'd rather not deal with those implications), is there another choice I have to deal with this?
If it doesn't make sense, please let me know and I'll do my best to clarify.
SOLUTION: I just added a reference to System.Web, which allowed my application to compile. I also wrapped the HttpContext reference in an "If HttpContext.Current isnot Nothing Then...End If" block, which causes it to skip over the code if it's not running as a web application, which is exactly what I was looking for.

If you reference the System.Web assembly, you should then be given access to HttpContext.Current, which is a reference to the currently running web app's HttpContext object. If the application is a normal Win32 app, this reference should be a null pointer. Thus in C# you would use:
if (HttpContext.Current == null)
or in VB you could use:
If HttpContext.Current Is Nothing Then
However, I have never tried doing something of this sort, so I can't guarantee the outcome. Let me know if that works for you.
Thanks,
C

Even if the app would compile you'd get the problem of no HttpContext in WinApp.
You could refactor the webapp so that instead of HttpContext it would use a service eg. IContextService or a bunch of services (ICacheService, ISessionService, etc.).
There would be two implementations of the service: one for the web app that would use HttpContext and one for the winapp which implementation would contain necessary logic to determine user preferences (language, etc.).
If the preferences are stored on the server you would need to implement some kind of service to communicate between your winapp and the server.

I think you could use a little bit of decoupling!
If you'd create a interface like this (in you BLL layer for instance)
public interface IPreferredLanguage
{
String PeferredLanguage { get; set; }
}
and you'de create two implementations:
In you website project:
public class WebPeferredLanguage : IPreferredLanguage
{
public String PeferredLanguage
{
get
{
return // retrieve the language from the http context
}
set
{
// set the preferred language in the HttpContext
}
}
}
In your winforms project:
public class WinformsPeferredLanguage : IPreferredLanguage
{
public String PeferredLanguage
{
get; set; // automatic properties
}
}
Hereafter you use Inversion of Control (Unity, StructureMap, MicroKernel) to configure in your webconfig that an instance of WebPeferredLanguage should be used and a singleton instance of WinformsPeferredLanguage should be returned in your winforms.
In your code whenever you need to know the language, you just ask the IoC container for the correct implementation of IPreferredLanguage, and it will return an object of the type which you have configured.
so in your bll you could program (for example):
public String GetEmailMessage()
{
var currentLanguage = IoC.Resolve<IPreferredLanguage>().PeferredLanguage;
return Resources[currentLanguage ].EmailMessage;
}
After writing this, I see that you wanted a VB.NET solution. Well, the examples still apply, only it's slightly different grammar (sorry if it's harder to read this way).

You can add System.Web.dll to your application and then use HttpContext. The problem is that there isnĀ“t a HttpContext in you win application, so you should use a web service or WCF to communicate between the two applications.

If possible, the probably best thing you could do is to completely remove the dependency on having a HTTP-context in the shared assembly.
For example, the method you mention which uses the HttpContext to get the user's preferred can be refactored so that the language is given as a parameter instead. When you call the method from your web application you can pass in the language from the HttpContext, and when you call it from the Windows application you will need to pass in the language from another source.

You should use
Thread.CurrentUICulture
to determine the user language. It is supported in WinForms and WebApplication as well.
The .NET framework set it for you in most cases.
You can set it up when your program/thread starts. In web application you can set it in Global.asax.cs in Application_BeginRequest.

Related

How to read internals of .NET Core console app from another app?

I have a .NET Core console application which instantiates some public classes with some public properties. It runs a loop which under certain conditions modifies these public properties. These properties are updated several times a second for the lifetime of the application.
Now I want another application with a user interface to present the data from the console application. How would I from one application get data present in the public properties of another application?
Not needed
I am only interested in public properties in public classes. I am not interested in private properties or fields or internal classes.
The properties are very frequently updated, so I do not want to write to a file. Nor do I want to log to some cloud service such as Azure Application Insights.
I would rather not do extensive or intrusive modifications to the console application (such as writing to a named pipe or a network socket) just for the other application to be able to read the data.
Thoughts
Is there any attribute I can annotate the classes or their properties with?
Do I have to refactor the console application into a class library that both the console application and the UI application reference? This would move out all the code into a class library and leave the console application with just a static main method that does one method call to run the code in the class library.
Can my UI application attach to the process of the console application?
To communicate between processes, you're limited to a few practical options (none of which you seem to want to do):
Named pipes
Some sort of socket based communication (not WCF in this case because you're using .NET Core)
This could be a custom protocol between your applications.
Could use an external message broker (e.g. RabbitMQ).
Could send UDP messages from the console app.
File based communication (doesn't seem ideal for your scenario given how chatty the interface is).
I solved this using System.Runtime.Loader.AssemblyLoadContext.
I load the assembly into my application at runtime and then instantiate its classes and read the public properties from my instance.
class Program
{
static void Main(string[] args)
{
var fileName = #"C:\temp\foo.dll";
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(fileName);
var type = assembly.GetType("MyApplication.Car");
dynamic carInstance = Activator.CreateInstance(type);
Console.WriteLine(carInstance.Color);
}
}
Another way to solve this was by importing the project as a project reference. This way I benefit from strong typing.

Removing singletons from large .NET codebase

The context:
(Note: in the following I am using "project" to refer to a collection of software deliverables, intended for a single customer or a specific market. I am not referring to "project" as it is used in Visual Studio to refer to a configuration that builds a single EXE or DLL, within a solution.)
We have a sizable system that consists of three layers:
A layer containing code that is shared across projects
A layer containing code that is shared across different applications within a project
A layer containing code that is specific to a particular application or website within a project.
The first two layers are built into DLL assemblies. The top layer is an assortment of EXEs and/or .aspx web applications.
IIRC, we have a number of different projects that use this pattern. All four share layer 1 (though often in slightly different versions, as managed by the VCS). Each of them has its own layer 2. Each of them has its own set of deliverables, which can range from a website, or a website and a background service, to our largest and most complex (and the bread-and-butter of our business) which consists of something like five independent web applications, 20+ console applications/background services, three or four independent web services, half-a-dozen desktop GUI apps, etc.
It's been our intent to push as much code into levels 1 and 2 as possible, to avoid duplicating logic in the top layers. We've pretty much accomplished that.
Each of layers 1 and 2 produce three deliverables, a DLL containing the code that is not web-related, a DLL containing the code that is web-related, and a DLL containing unit tests.
The problem:
The lower levels were written to make extensive use of singletons.
The non-web DLL in layer 1 contains classes to handle INI files, logging, a custom-built obect-relational mapper, which handles database connections, etc. All of these used singletons.
And when we started building things on the web, all of those singletons became a problem. Different users would hit the website, log in, and start doing different things. They'd do something that generated a query, which would result in a call into the singleton ORM to get a new database connection, which would access the singleton configuration object to get the connection string, and then the connection would be asked to perform a query. And in the query the connection would access the singleton logger to log the SQL statement that was generated, and the logger would access the singleton configuration object to get the current username, so as to include it in the log, and if someone else had logged in in the meantime that singleton configuration object would have a different current user. It was a mess.
So what what we did, when we started writing web applications using this code base was to create a singleton factory class, that was itself a singleton. Every one of the other singletons had a public static instance() method that had been calling a private constructor. Instead, the public static instance() method obtained a reference to the singleton factory object, then called a method on that to get a reference to the single instance of the class in question.
In other words, instead of having a dozen classes that each maintained its own private static reference, we now had a single class that maintained a single static reference, and the object that it maintained a reference to contained a dozen references to the other, formerly singleton classes.
Now we had only one singleton to deal with. And in its public static instance() method, we added some web-specific logic. If we had an HTTPContext and that context had an instance of the factory in its session, we'd return the instance from the session. If we had an HTTPContext, and it didn't have a factory in its session, we'd construct a new factory and store it in the session, and then return it. If we had no HTTPContext, we'd just construct a new factory and return it.
The code for this was placed in classes we derived from Page, WebControl, and MasterPage, and then we used our classes in our higher-level code.
This worked fine, for .aspx web applications, where users logged in and maintained session. It worked fine for .asmx web services running within those web applications. But it has real limits.
In particular, it won't work in situations where there is no session. We're feeling pressure to provide websites that serve a larger user base - that might have tens or hundreds of thousands of users hitting them dynamically. Up to now our users have been pretty typical desktop business users. They log into our websites, and stay in them much of the day, using our web apps as an alternative to a desktop app. A given customer might have as many as six users who might use our websites, and while we have a thousand or more customers, combined they don't make for all that heavy a load. But our current architecture will not scale to that.
We're also running into situations where ASP.NET MVC would be a better fit for building the web UI than .aspx web forms. And we're exploring building mobile apps that would be communicating with stand-alone WFC web services. And while in both of these, it looks like it's possible to run them in an environment that has a session, it looks to limit their flexibility and performance fairly severely.
So, we're really looking at ways to eliminate these singletons.
What I'd really like:
I'm trying to envision a series of refactors, that would eventually lead to a better-structured, more flexible architecture. I could easily see the advantages of an IoC framework, in our situation.
But here's the thing - from what I've seen of IoC frameworks, they need their dependencies provided to them externally via constructor parameters. My logger class, for example, needs an instance of my config class, from which to obtain the current user. Currently, it is using the public static instance() method on the config class to obtain it. To use an IoC framework, I'd need to pass it as a constructor.
In other words, from where I sit, the first, and unavoidable task, is to change every class that uses any of these singletons so as to take the singleton factory as a constructor parameter. And that's a huge amount of work.
As an example, I just spent the afternoon doing exactly that, in the level 1 libraries, to see just how much work it is. I ended up changing over 1300 lines of code. The level 2 libraries will be worse.
So, are there any alternatives?
Typically, you should try to wrap the contextual information into its own instance and provide a static accessor method to refer to it. For example, consider HttpContext and its available every where in web application via HttpContext.Current.
You should try to devise something similar so that instead of returning singleton instance, you would return the instance from the current context. That way, you need to not change your consumer code that refers to these static methods (e.g. Logger.Instance()).
I generally roll-up information such as logger, current user, configuration, security permissions into application context (can be more than one class if need arises). The AppContext.Current static method returns the current context. The method implementation goes something like
public interface IContextStorage
{
// Gets the stored context
AppContext Get();
// Stores the context, context can be null
void Set(AppContext context);
}
public class AppContext
{
private static IContextStorage _storageProvider, _defaultStorageProvider;
public static AppContext Current
{
get
{
var value = _storageProvider.Get();
// If context is not available in storage then lookup
// using default provider for worker (threadpool) therads.
if (null == value && _storageProvider != _defaultStorageProvider
&& Thread.CurrentThread.IsThreadPoolThread)
{
value = _defaultStorageProvider.Get();
}
return value;
}
}
...
}
IContextStorage implementations are application specific. The static variables _storageProvider gets injected at the application start-up time while _defaultStorageProvider is a simple implementation that looks into current call context.
App Context creation happens in multiple stages - for example, a global information such as configuration gets read and cached at application start-up while specific information such as user & security gets formed at authentication stage. Once all info is available, the actual instance is created and stored into the app specific storage location. For example, desktop application will use a singleton instance while web application can probably store the instance into the session state. For web application, you may have logic at start of each request to ensure that the context is initialized.
For a scalable web applications, you can have a storage provider that will store the context instance into the cache and if not present in the cache then re-built it.
I'd recommend starting by implementing "Poor Man's DI" pattern. This is where you define two constructors in your classes, one that accepts an instance of the dependencies (IoC), and another default constructor that new's them up (or calls a singleton).
This way you can introduce IoC incrementally, and still have everything else work using the default constructors. Eventually when you have IoC being used in most places you can start to remove the default constructors (and the singletons).
public class Foo {
public Foo(ILogger log, IConfig config) {
_logger = log;
_config = config;
}
public Foo() : this(Logger.Instance(), Config.Instance()) {}
}

How to access Session values from layers beneath the web application layer

We have many instances in our application where we would like to be able to access things like the currently logged in user id in our business domain and data access layer. On log we push this information to the session, so all of our front end code has access to it fairly easily of course. However, we are having huge issues getting at the data in lower layers of our application. We just can't seem to find a way to store a value in the business domain that has global scope just for the user (static classes and properties are of course shared by the application domain, which means all users in the session share just one copy of the object). We have considered passing in the session to our business classes, but then our domain is very tightly coupled to our web application. We want to keep the prospect of a winforms version of the application possible going forward.
I find it hard to believe we are the first people to have this sort of issue. How are you handling this problem in your applications?
I don't think having your business classes rely on a global object is that great of an idea, and would avoid it if possible. You should be injecting the necessary information into them - this makes them much more testable and scalable.
So rather than passing a Session object directly to them, you should wrap up the information access methods that you need into a repository class. Your business layer can use the repository class as a data source (call GetUser() on it, for example), and the repository for your web app can use session to retrieve the requested information (return _session.User.Identity).
When porting it to winforms, simply implement the repository interface with a new winform-centric class (i.e. GetUser() returns the windows version of the user principal).
In theory people will tell you it's a bad business practice.
In practice, we just needed the data from the session level available in the business layers all the time. :-(
We ended up having different storage engines united under a small interface.
public interface ISessionStorage
{
SomeSessionData Data {get;set;}
...
.. and most of the data we need stored at "session" level
}
//and a singleton to access it
public static ISessionStorage ISessionStorage;
this interface is available from almost anywhere in our code.
Then we have both a Session and/or a singleton implementation
public WebSessionStorage
{
public SomeSessionData Data
{
get { return HttpContext.Current.Session["somekey"] as SomeSessionData;}
set { HttpContext.Current.Session["somekey"] = value;}
}
public WebFormsSessionStorage
{
private static SomeSessionData _SomeSessionData; //this was before automatic get;set;
public SomeSessionData
{
get{ return _SomeSessionData;}
set{ _SomeSessionData=value; }
}
}
On initing the application, the website will do a
Framework.Storage.SessionStorage = new WebSessionStorage();
in Global.asax, and the FormsApp will do
Framework.Storage.SessionStorage = new WebFormsSessionStorage();
I agree with Womp completely - inject the data down from your front-end into your lower tiers.
If you want to do a half-way cheat (but not too much of a cheat), what you can do is create a very small assembly with just a couple POCO classes to store all of this information you want to share across all of your tiers (currently logged-in username, time logged in, etc.) and just pass this object from your front-end into your biz/data tiers. Now if you do this, you MUST avoid the temptation to turn this POCO assembly into a general utility assembly - it MUST stay small or you WILL have problems in the future (trust me or learn the hard way or ask somebody else to elaborate on this one). However, if you have this POCO assembly, injecting this data through the various tiers becomes very easy and since it's POCO, it serializes very well and works nicely with web services, WCF, etc.

Getting ApplicationState in asp.net without HttpContext

I got a webapp that stores a config object in ApplicationState.
This object contains the connection string to the database among other things.
Sometimes i start a async thread to do a few longer running tasks, like sending emails and updating the database.
However since this thread don't have a HttpContext i can't get at the config object.
I know this design that everything depends on HttpContext is bad, but thats too late to change now.
Looking at reflector i see that the HttpContext class just uses a static internal class to get the ApplicationState. Is there any other way to get at it?
All those internal classes in .net are really annoying.
Just pass whatever you like to your thread when you start it. Use a ParameterizedThreadStart delegate to start it instead of just a ThreadStart delegate. You could either pass it HttpContext.Current, or else bundle together the information you want your thread to have, and pass it.
If you really need access to Application State (or similar) from async handlers you should modify your HttpApplication subclass (e.g. Global.asax) to store the Application State instance (this.Application) to a static property during Application_Start:
public static HttpApplicationStateWrapper State { get; private set; }
protected void Application_Start()
{
State = new HttpApplicationStateWrapper(this.Application);
}
It would be more appropriate to use a DI framework to register this instance, but if you have one available you could probably avoid the use of Application State altogether for storing config. Further, there is a configuration framework in .NET that directly addresses this need and provides the ability to read configuration from anywhere.

Shared/Static variable in Global.asax isolated per request?

I have some ASP.NET web services which all share a common helper class they only need to instantiate one instance of per server. It's used for simple translation of data, but does spend some time during start-up loading things from the web.config file, etc. The helper class is 100% thread-safe. Think of it as a simple library of utility calls. I'd make all the methods shared on the class, but I want to load the initial configuration from web.config. We've deployed the web services to IIS 6.0 and using an Application Pool, with a Web Garden of 15 workers.
I declared the helper class as a Private Shared variable in Global.asax, and added a lazy load Shared ReadOnly property like this:
Private Shared _helper As MyHelperClass
Public Shared ReadOnly Property Helper() As MyHelperClass
Get
If _helper Is Nothing Then
_helper = New MyHelperClass()
End If
Return _helper
End Get
End Property
I have logging code in the constructor for MyHelperClass(), and it shows the constructor running for each request, even on the same thread. I'm sure I'm just missing some key detail of ASP.NET but MSDN hasn't been very helpful.
I've tried doing similar things using both Application("Helper") and Cache("Helper") and I still saw the constructor run with each request.
You can place your Helper in the Application State. Do this in global.asax:
void Application_Start(object sender, EventArgs e)
{
Application.Add("MyHelper", new MyHelperClass());
}
You can use the Helper that way:
MyHelperClass helper = (MyHelperClass)HttpContext.Current.Application["MyHelper"];
helper.Foo();
This results in a single instance of the MyHelperClass class that is created on application start and lives in application state. Since the instance is created in Application_Start, this happens only once for each HttpApplication instance and not per Request.
It's not wise to use application state unless you absolutely require it, things are much simpler if you stick to using per-request objects. Any addition of state to the helper classes could cause all sorts of subtle errors. Use the HttpContext.Current items collection and intialise it per request. A VB module would do what you want, but you must be sure not to make it stateful.
I 'v done something like this in my own app in the past and it caused all kinds of weird errors.
Every user will have access to everyone else's data in the property. Plus you could end up with one user being in the middle of using it and than getting cut off because its being requested by another user.
No there not isolated.

Resources