Selfhost Web API parameter passing - c#

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.

Related

MVC Page Load instantiate several controllers with shared resources

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

Ajax call to the Asp.net Web API controller

As part of the project we have implemented ASP.Net Web API, which returns the Json data, which is consumed by the Javascript using Angular JS on the client.
Controller code is straight forward (Trimmed description):
public class CardController : ApiController
{
// code
[HttpGet]
public CardDataGetUI GetCardDataUI(int userID, int dashBoardID, int cardID)
{
// Access the application Cache object using HttpRuntime (System.Web.Caching)
var blCache = HttpRuntime.Cache;
// Create a user specific BL access key by concatenating the user ID
string userBLAccessKey = WebAPIConstant.BlUserDashboardCard + userID;
// Access the BL object stored in the Cache
accessBL = (Bl)blCache[userBLAccessKey];
// Other Code
// Fetch the data for the control being passed
cardDataUI = accessBL.GetCardDataUI(dashBoardID, cardID);
return (cardDataUI)
}
}
The above mentioned GetCardDataUI delivers the card data for different type of control like chart, map and grid on a same UI screen, so what UI does is make an Asynchronous call to all in one go, currently I have BL (business layer) object being accessed from application wide cache, which is an issue for Multi threaded access, as they would share same object, so I have converted that to a local copy and initialized the one for each call to the controller. However that is also good enough till the each ajax call is having it's unique controller instance to call the method. However in this case it seems the http call they make have same instance thus modifying the input variable of each call thus leading to unexpected result and exception, since it is modifying the internal DS at run time. It is akin to calling the static method
Ideally I did not expected a multi-threaded call to the business layer, but it seems in Angular JS client has to make such calls, they cannot be synchronous.
Currently I have resolved the situation by introducing a lock in the controller, which certainly allows one thread at a time
However was looking for a solution like each Ajax call can have it's own controller instance, when it make the http get call.
We also have an option of modifying the above mentioned controller method like:
public CardDataGetUI[] GetCardDataUI(int userID, int dashBoardID, int[] cardID)
{
// Code
}
In this case there will be one call for all cards and I will call the data fetch in a for loop, thus synchronizing the operation, but this is not much different from locking the controller, preferable will be a separate controller instance for each AJAX call
Any suggestion?

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...

How to give a value to a variable that is in a WebService?

I am making a project using WebServices in C#. I wanted to ask you, how can I give a value to a variable from Client to a Web Service?
For example:
In the web service I have a variable and two Methods, getVariable() and setVariable(bool a);
bool var = false;
[WebMethod]
public void setVariable(bool a)
{
var = a;
}
[WebMethod]
public bool getVariable()
{
return var;
}
This is how my web service looks (it's simple because I am learning).
My client:
//In the client I added the web service as a Service Reference and added this code:
ServiceReference.ServiceSoapClient obj = new ServiceReference.ServiceSoapClient();
private void Form_Load(object sender, EventArgs e)
{
obj.setVariable(true);
label1.Text = obj.getVariable().ToString();
}
And when I load my form, the label1.Text isn't equal with "True" but with "False"!! Which means that it didn't execute this code: obj.setVariable(true);
My professor said in the class something that WebService are now "full...." (but I couldn't hear it well), he said you have to find a way to make WebServices "ful..."
Can someone help me ?
Web services are stateless by default, which means that they don't retain state between calls. So a value set in one call won't be available for usage by the next call.
If you need a stateful service, there are several ways to go. this is probably the simplest.
It sounds like you are doing this for learning purposes, in which case I suggest reading up on why it is not a good practice to develop using stateful services. Try this one for starters.
Since web services are stateless you can't do what you are trying to do.
Although you have only one client instance, for each call a server-side instance gets created. That means that in the first call you set the variable on an object, which then goes out of scope (since it's tied to that request). When you do make the second call, a new instance of your service gets created and this new instance obviously has no knowledge of the previous one.
If you want to do something like that you need the save the state. This can be done in various ways:
Save the value in the Application object (HttpContext.Current.Application("myvar") = a)
Save it in session state (you need to add an attribute to the service class to enable session state, then you do the same as with the Application but accessing HttpContext.Current.Session
Save it in a database
Save it in a file
...
#I4V - Thanks for your comment on my post.
I just added static before the bool variables and it worked.

Injecting host from HttpContext into Service layer

I need to apply filtering by requesting host name on all database calls in my Web API service.
This filtering works like so:
lookup the Site to profile against based on the requesting hostname
Apply Site.Id on all subsequent data access calls made in the request
Essentially a global filter so so that data returned by the API service is always contained to the host.
One solution would be to pass the host name in as an argument on all my service methods like so:
public IEnumerable<Profiles> GetProfiles ()
{
var host = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
return profilesService.Get(host);
}
But since this is a consistent rule on all requests I would like to come up with a more elegant way to handle this so my service calls are just profileSerivce.Get();
I think I need to inject a ISiteLocator into my service layer that has either the host name or even better the Id already retrieved from the database that I can then apply. But I'm struggling with this on how and where I can reference the HttpContext to get the host name and also if it was possible to optimise this using StructureMap lifecycles.
I think I need to inject a ISiteLocator into my service layer
It seems to me you are heading into the right direction.
I'm struggling with this on how and where I can reference the
HttpContext
This is really simple actually. Define the ISiteLocator in your business layer and define an AspNetSiteLocator implementation into your ASP.NET web application, preferably close to (or inside) your Composition Root. That implementation might look like this:
public class AspNetSiteLocator : ISiteLocator
{
private readonly ISiteRepository siteRepository;
public AspNetSiteLocator(ISiteRepository siteRepository)
{
this.siteRepository = siteRepository;
}
Site ISiteLocator.GetCurrentSite()
{
return this.siteRepository.GetById(CurrentHostName);
}
private static string CurrentHostName
{
get
{
return HttpContext.Current.Request
.ServerVariables["SERVER_NAME"];
}
}
}
that has either the host name or even better the Id already retrieved
from the database
Try to let your ISiteLocator return data in a way that is most convenient to the consumers of that locator. In my example I returned a Site entity (if you have such an entity in your domain). This is probably more convenient than the host name or the Id, since consumers possibly have to query for the site again thereselves. However, perhaps Id is the most convenient, but that's up to you to find out.
how [...] to optimise this using StructureMap lifecycles
The implementation above doesn't have any state, so it can be registered with any lifetime; singleton for instance. However, every call to ISiteLocator.GetCurrentSite() will result in a new request to the ISiteRepository, which can cause too much overhead. In that case you probably want an implementation that stores the Site in a private field and always returns that instance. In that case you shoud register that implementation on a 'Per Web Request' basis (since the SERVER_NAME will not change during the request).

Categories