MVC Page Load instantiate several controllers with shared resources - c#

I have detected, that during loading the main page several controllers are instantiated (I think because the main page is built from several parts). The controllers instantiate the API classes to query some data through them. I was wondering how and where I could share the same API class instance between them.
I can imagine such a code:
class HomeController : Controller
{
private MyApi Api;
public HomeController()
{
this.Api = get the pervious MyApi instance form somewhere
if (this.Api == null) // 1st time
{
this.Api = new MyApi();
put this instance to somewhere to share between controllers
}
This "somewhere" is not a session, because next page load needs another MyApi instance. It must go to an object property which remains intact during the whole page load process, but is dismissed when the html result is generated. It must be really a simple thing, but I really don't know where it is :( Could somebody help me?

You can consider using Microsoft Unity Framework in your application.
Using Unity Dependency Injector you will be able to inject instances of MyApi class into the any controller and avoid writing " if (this.Api == null) " these types of checks and also managing instances of it in some Session or Application level variables, which makes code dirty.
For this specific problem "It must go to an object property which remains intact during the whole page load process, but is dismissed when the html result is generated", You can configure Unity Injected object to have a life time of "Scoped". Meaning, the object will be created once per request.
Here's is a link on configuring Unity in an asp.net core application
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2

Related

Selfhost Web API parameter passing

I have middle ware with different components interacting with each other. I'm building now a selfhost Web API using OWIN and .NET WebAPI to interact with 3rd parties. My problem is that I need to pass an object reference to my controller so when the controller is called via a GET or POST request it can call function of the passed object. Dependency injection is not helping me in this case cause I need to pass a reference of an existing object and not create a new one.
The WebAPI is created in the ExternalWebAPI class start function:
public virtual void Start()
{
server = WebApp.Start<WebAPIStartup>(url: baseAddress);
UpdateStatus("Active","True");
}
Right now my controller looks like this:
class TradesController:ApiController
{
TradeRequest PostTradeRequest(TradeRequest tradeRequest)
{
return tradeRequest;
}
}
What I want to be able to do is to pass a reference to the TradesController of the ExternalWebAPI class using thisso from TradesController I would be bale to call ExternalWebAPI functions. I looked into DI, but I haven't found a good way to do it since it important to pass the instance of the ExternalWebAPI class that has started up the WebAPI cause it has other methods and events that has to be called once the TradesController's PostTradeRequest is called.
I think you are going down the wrong path here. Your API should take data in and send data out. It should not hold references to anything or call functions on those references. Call you API for the data you need to update your local reference and then call the function on that object as needed.

How can share an object between an ASP.Net page and other projects

I have an object (ClientConfiguration) that I use on almost every page on my site, as well as in many methods that exist in related projects that get compiled into the website.
What I am doing now is creating and populating the object on each page load, and storing it in the HttpContext. This works great for anything in the UI project; and for anything in the dll projects, I pass the ClientConfiguration to any methods that may need to use it.
What I would rather do is have a "global" property that is shared among all of the related projects so I don't have to pass it around.
Is there a good way to accomplish this?
After you add System.Web.dll as reference in your other library projects, you can access the object in HttpContext directly, no need to pass as parameter.
This depends a bit on where initial configuration is being stored (xml file, database or something else) but you’ll see the point.
If these are global configuration settings that are same for all application users you can create a class like this
public class Config
{
public static ClientConfiguration Current
{
get
{
if (HttpContext.Current.Application["clientconfig"] == null)
{
//Fill object from database
}
return HttpContext.Current.Application["clientconfig"] as ClientConfiguration;
}
set
{
//store object in database
//invalidate what is stored in application object
//so that it will be refreshed next time it's used
HttpContext.Current.Application["clientconfig"] = null;
}
}
}
This will store the ClientConfiguration in global Application object and make it available in all pages so you don’t have to create it in page load.
You can just use it like this
private void Foo()
{
ClientConfiguration config = Config.Current;
}
If you have multiple projects that need to share same data then it’s best to store the object in database or in shared XML file and create new class library project so that you can just include reference to the Config class.

SignalR multiple hubs on different paths in same application?

I have an application which contains multiple hubs all on unique paths, so when calling the default :
routes.MapHubs("path", new HubConfiguration(...));
It blows up saying that the signalr.hubs is already defined (as mentioned here MapHubs not needed in SignalR 1.01?).
Now I can understand that it should only be called once, but then you will only get 1 path, so is there any way to handle a path per hub scenario? like how with MVC you specify the controller and action? so something like:
routes.MapHub<SomeHub>("path", new HubConfiguration(...));
== Edit for more info ==
It is mentioned often that you should never need to call this map hubs more than once, and in most scenarios I can agree, however I would not say that this is going to be the case for all applications.
In this scenario it is a website which at runtime loads any plugins which are available, each plugin is exposed the dependency injection framework to include its dependencies and the route table to include its routes. The hubs may have nothing to do with each other (other than the fact that they are both hub objects). So the hubs are not all known up front and are only known after the plugins are loaded, and yes I could wait until after this and try binding the hubs there, however then how do I have custom routes for each one then?
This seems to be a case of SignalR trying to abstract a little too much, as I dont see it being a bad idea to have custom routes rather than the default "/signalr", and as the routes all have different responsibilities it seems bad to have one entry route for them all.
So anyway I think the question still stands, as I dont see this as being a bad use case or bad design it just seems to be that I want to be able to have a route with a hub applied to it, much like in mvc you apply a controller and action to a route.
You shouldn't need more than the signalr.hubs route. If you point your browser to that route, you will see it automatically finds all public types assignable to IHub and creates a JavaScript proxy for them. You can interact with different hubs by name from JavaScript, i.e. if you have the following Hub:
public class GameHub : Hub
You can connect to that specific hub by doing:
var gameHubProxy = $.connection.gameHub;
You can also explicitly specify a name for your hub by adding the HubNameAttribute to the class:
[HubName("AwesomeHub")]
public class GameHub : Hub
You can then retrieve the specific proxy by doing
var awesomeHubProxy = $.connection.awesomeHub;
UPDATE:
I'm not sure whether SignalR will be able to run on multiple paths in the same application. It could potentially mess things up and the default assembly locator won't be able to pick up hubs loaded at runtime anyway.
However, there is a solution where you can implement your own IAssemblyLocator that will pick up hubs from your plugin assemblies:
public class PluginAssemblyLocator : DefaultAssemblyLocator
{
private readonly IEnumerable<Assembly> _pluginAssemblies;
public PluginAssemblyLocator(IEnumerable<Assembly> pluginAssemblies)
{
_pluginAssemblies = pluginAssemblies;
}
public override IList<Assembly> GetAssemblies()
{
return base.GetAssemblies().Union(_pluginAssemblies).ToList();
}
}
After you've loaded your plugins, you should call MapHubs and register an override of SignalRs IAssemblyLocator service:
protected void Application_Start(object sender, EventArgs e)
{
// Load plugins and let them specify their own routes (but not for hubs).
var pluginAssemblies = LoadPlugins(RouteTable.Routes);
RouteTable.Routes.MapHubs();
GlobalHost.DependencyResolver.Register(typeof(IAssemblyLocator), () => new PluginAssemblyLocator(pluginAssemblies));
}
NOTE: Register the IAssemblyLocator AFTER you've called MapHubs because it will also override it.
Now, there are issues with this approach. If you're using the static JavaScript proxy, it won't be re-generated every time it's accessed. This means that if your /signalr/hubs proxy is accessed before all plugins/hubs has been loaded, they won't be picked up. You can get around this by either making sure that all hubs are loaded by the time you map the route or by not using the static proxy at all.
This solution still requires you to get a reference to your plugin assemblies, I hope that's feasible...

Custom ASP.NET callback-based routing; dynamic ASPX page instantiation and rendering

I'm working on a small school project, an ASP.NET C# website; we're working with a Web Application, using a Global.asax file to centralize request logic.
Anyway, my colleague and I are responsible for the coding in our group, and we both come as reasonably experienced PHP developers. We both rather enjoy working with the architectural style used by the PHP framework Laravel, using routes (callbacks associated with) as the "controllers", and (despite it being a square peg, round hole issue) are trying to replicate that functionality for this project.
This is no easy task; I've implemented the IRouteHandler interface as a CallbackRouteHandler in an attempt to start replicating this functionality:
public class CallbackRouteHandler : IRouteHandler
{
public Func<RequestContext, IHttpHandler> Callback { get; protected set; }
public CallbackRouteHandler(Func<RequestContext, IHttpHandler> callback)
{
this.Callback = callback;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return this.Callback(requestContext);
}
}
Unfortunately this is about as far as I've gotten. I'm reading through the ASP.NET Page Life Cycle Overview, attempting to understand better the entire process.
What we're stuck on is programmatically loading ASPX files (rather, instantiating as Page objects) in the scope of a given route callback. We were hoping there would be a reasonably easy way to accomplish, within the scope of the callback, something like:
// instantiate the target ASPX page object
OurSite.SomeNamespace.SomePage page = new OurSite.SomeNamespace.SomePage();
// manipulate the page object, setting public properties, etc.
page.SomeControl.Text = "Foobar!";
// eventually "render" the file to somehow; at this point, the
// page and it's associated code-behind events take control
page.Render();
I'm having trouble understanding both: 1) How to do this? 2) When (relative to the aforementioned page life-cycle) to do this.
How (if at all) can one accomplish this sort of functionality? I'm seeing that this process, hidden away by ASP.NET, is seemingly very complicated, but surely others have tread down this path before.
I went with MVC for this project, however I've since had the opportunity to dissect the ASP.NET request pipeline a bit, and have implemented custom routing solutions as warranted.

Does Resolve<T>() return objects per-session?

In Microsoft Unity IoC, if I call Resolve<SomeType>(), can I guarantee that the object returned is the one that was created during the current session?
For example, three users sign on, and let's say that the object of SomeType that gets created in the container has different values for each user. Will a call to Resolve return the object that was created for the current user? Or would it do something stupid like return the last one that was created?
I'm having troubles testing this myself due to some environment problems and I need to check something in soon, so if someone could answer this it would be very helpful!
Edit
Forgive me for I am very new to Unity, but based on what I read here, it seems like I should be able to register objects in the container with a unique name and retrieve them by that name. So, wouldn't I be able to use a session ID or some other value that persists within a session to retrieve my object?
Oh wow, lifetime management using Unity in am MVC app. Where do I start?
First of all, session singletons are not really possible as there is no ASP.NET system that will guarantee that the same instance will be used between requests in the same session. The session can mimic the same object persisted within the session by serializing and deserializing it between requests.
Transient instances - i.e. simple registrations without lifetime management specification are sufficient 99% of the time. This implies that an instance of registered type will be created every time it is needed.
It is very rarely that you need instances to live throughout the lifetime of the request. However when you need those, you really need those. A connection to a DB is a perfect candidate for this. Request singletons, on the other hand are much easier to create and manage.
The most elegant solution is to use Unity's child container feature. A child container can be created at the beginning of the request, disposed at the end of the request (as an added bonus it will dispose all ContainerControlledLifetimeManager instances).
When creating a child container, all registrations are still available from the parent container, so you need to register request specific stuff with the child container.
Here is pseudo-code to get this working:
private void Application_Start() {
_parentContainer = new UnityContainer();
//creates a transient registration, available at any point in the app.
_parentContainer.RegisterType<IParentIntf, ParentIntfImpl>();
ControllerBuilder.Current.SetControllerFactory(new ServiceLocatorControllerFactory());
}
private void Application_BeginRequest() {
var childContainer = _parentContainer.CreateChildContainer();
//registers a request "singleton"
//This registration is a type registration, an instance of RequestInterfaceImpl
//will be created when needed and then kept in the container for later use.
childContainer.RegisterType<IRequestInterface,RequestInterfaceImpl>(new ContainerControlledLifetimeManager());
//save the child container in the context, so we can use it later
HttpContext.Items["childContainer"] = childContainer;
}
private void Application_EndRequest() {
//dispose the child container
((IUnityContainer)HttpContext.Items["childContainer"]).Dispose();
}
One other thing that needs to be done is to override the Controller Factory to use the child container to create controllers. Controller are the first point of entry into the application and they could simply take a dependency on other components in their constructor.
public class UnityControllerFactory : DefaultControllerFactory {
#region IControllerFactory Members
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) {
IController controller;
controllerName = controllerName.ToLower();
var container = ((IUnityContainer)HttpContext.Items["childContainer"])
if(container.IsRegistered<IController>(controllerName))
controller = container.Resolve<IController>(controllerName);
else
controller = base.CreateController(requestContext, controllerName) ;
return controller;
}
}
The default behaviour will be to return a new instance for each resolve call, this isn't what you want.
It would be possible to create and resolve the same instance within a session, but there is no built in support as far as I know. You would have to write your own lifetime manager, and then use this when registering your type.
There is a lifetime manager that can do per thread instances, but this isn't useful for sessions as threads will get re-used, and resolve would need to also work across multiple requests to be truly session-scoped.
It's entirely possible that someone has written a lifetime manager for this.

Categories