Pass ServiceBase class instance to ApiController hosted on it - c#

I'm developing a Windows Service with a RESTFul web service hosted on it. I'm going to communicate with the windows service throught the windows service.
This is my project structure:
These are my classes implementation.
namespace WindowsService_HostAPI
{
public partial class SelfHostService : ServiceBase
{
private int _value;
private HttpSelfHostServer _server;
private static readonly ILog _log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public int Value
{
get { return _value; }
set { _value = value; }
}
public SelfHostService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute(
name: "API",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
_server = new HttpSelfHostServer(config);
_server.OpenAsync().Wait();
}
protected override void OnStop()
{
if (_server != null)
_server.CloseAsync().Wait();
}
}
}
And ValuesController:
namespace WindowsService_HostAPI.Controllers
{
public class ValuesController : ApiController
{
[HttpGet]
[Route("api/Value/")]
public HttpResponseMessage GetValue()
{
HttpResponseMessage response = null;
return response;
}
[HttpPost]
[Route("api/Value/{value}")]
public HttpResponseMessage SetValue(int value)
{
HttpResponseMessage response = null;
return response;
}
}
}
This is only an example, but I need to communicate the ApiController with the Windows Service class.
I have to modify SelfHostService.Value property when someone do a Post (method SetValue) setting value passed. How can I do that?

I need to create a class instance and keep it alive until Windows
Service stops
The right way to do what you want with Web API is to use IDependencyResolver. Here's the sample (it uses Unity, but you can use any container).
The main concept is that you build up a contract for dependency, e.g.:
public interface IValueProvider
{
public int Value { get; set; }
}
then implement this contract somewhere (you can even implement it in SelfHostService, but, actually, you shouldn't), configure DI-container to use your implementation, and use it from controller:
public class ValuesController : ApiController
{
private readonly IValueProvider _valueProvider;
public ValuesController(IValueProvider valueProvider)
{
_valueProvider = valueProvider;
}
// the rest of code here
}
Note, that usually DI-containers allow to build parent/child hierarchy.
To reflect this, Web API DI approach uses scopes for this (see IDependencyResolver.BeginScope method).
There are global scope and child scopes. The Web API host creates global scope when it starts. This scope lives until host listens for requests. Host creates child scopes, when request is received, and host needs to create a controller to respond.
DI containers differ a little, when manage lifetime of objects, that were created using container. But the common is to place dependencies to the scope, where they needed. So, if you want to build some "global" dependency, then you need to place it into global scope.

Related

How can I get the base route while doing service configuration in ASP.NET Core?

I have a series of services I am configuring in my application and one of those services require a base URL to a specific route so I can create links based on it. So if we have:
My Controller
[Route("api/v1/fancy")]
public class FancyController {
[HttpPost]
[Route("{fancyID}")]
public async Task<IActionResult> SubmitFancy(string fancyID){
// Do fancy stuff
}
}
My business class
public class Business {
private string _baseUrl;
public Business(string baseUrl){
_baseUrl = baseUrl
}
}
My Startup.cs
...
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<Business>(provider => {
Business business = new Business("http://someweb.com/api/v1/fancy"); //TODO:REMOVE Hard Coded
return business;
}
services.AddRazorPages();
}
...
I have tried to use UrlHelper by adding a few more scoped services for IActionContextAccessor and IUrlHelperFactory, but I am getting null on ActionLink and RouteUrl methods, and I am not sure why.
Any ideas as to how I would go about solving this issue?
Please let me know if you need more clarification.
Thank you very much.
Inject a LinkGenerator & IHttpContextAccessor into your service;
public class Business {
private readonly LinkGenerator generator;
private readonly IHttpContextAccessor accessor;
public Business (LinkGenerator generator, IHttpContextAccessor accessor){...}
public void Foo(){
var context = accessor.HttpContext;
var link = generator.GetUriByAction(
context,
"SubmitFancy",
"Fancy",
new { fancyID="..." });
}
}
services.AddScoped<Business>();
You can use LinkGenerator without a reference to a HttpContext, but you'd need to supply the host, scheme and pathBase from somewhere else. Either from configuration, or perhaps by implementing middleware to capture them from the first request.
You can't use a string for an attribute routing. You need a CONSTANT string. Constants are immutable values which are known at compile time and do not change for the life of the program.
But if you need a route to use in ajax or httpclient, it takes several steps to get a string from appsettings.
create AppUrl section in appsettings.json
"AppUrl": {
"BusinessUrl": "http//..",
.... another urls if needed
},
2.Create class for this section
public class AppUrlSettings
{
public string BusinessUrl{ get; set; }
....another urls
}
configure settings in startup
services.Configure<AppUrlSettings>(Configuration.GetSection("AppUrl"));
now you can use them like this
public class MyClass
{
private readonly IOptions<AppUrlSettings> _appUrls;
public MyClass (IOptions<AppUrlSettings> appUrls)
{
_appUrls = appUrls;
}
public string GetBusinessUrl()
{
return _appUrls.Value.BussinesUrl;
}
}

BaseController for HttpClient Instance

I have some API client to make request. Those are described in startup.
Simply, is it make sense to create HttpClient via base class and calling common request methods from base. Or each controller should create own client ? Is there will be a problem ?
Base
public class BaseController : ControllerBase
{
public HttpClient client;
public BaseController(IHttpClientFactory factory, string clientName)
{
client = factory.CreateClient(clientName);
}
public async Task<IActionResult> Get(string query)
{
}
}
Foo
public class FooController : BaseController
{
public FooController(IHttpClientFactory factory) : base(factory, "fooclient")
{
}
[HttpGet]
public async Task<IActionResult> Get(int id)
{
return await Get($"Foo/Get/{id}");
}
}
There's nothing technically wrong with this approach, but it's preferable to use typed clients. The way that is done is by creating a "service" class which will own the client:
public class FooService
{
private readonly HttpClient _httpClient;
public FooService(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
...
}
Then, you register this in ConfigureServices:
services.AddHttpClient<FooService>(c =>
{
// configure your HttpClient
});
Finally, you inject this service class into your controller:
public class FooController : ControllerBase
{
private readonly FooService _fooService;
public FooController(FooService fooService)
{
_fooService = fooService ?? throw new ArgumentNullException(nameof(fooService));
}
...
}
This then serves to encapsulate your HttpClient logic. You simply add methods to the service to do things the controller needs and the service makes the actual HttpClient requests to do that. That makes it infinitely easier to change things if the API you're utilizing should change. You just change the service and you're good to go, instead of having to track down every place you used HttpClient to interact with this API, which is a much more difficult task.
Additionally, having the client be typed gives you the ability to configure it once for all, as well as add things like retry and exception handling policies in one place. Since the client is injected for a particular type (i.e. FooService) there's no magic strings for the client name that you could fat finger or otherwise mess up.

Provide user information from signalr request in business logic layer using autofac

I have an ASP.NET MVC 5 Application with a SignalR 2 hub and using autofac for the DI.
The entire business logic is encapsulated in manager classes in their own layer. Some manager methods need informations about the current logged in user (UserId, TenantId, ..).
I solved this problem by injecting an AuthorizationProvider into each manager class that needs the user information.
public interface IAuthorizationProvider
{
long? GetUserId();
long? GteTenantId();
}
public class MyManager : IMyManager
{
private IAuthorizationProvider _authorizationProvider;
public MyManager(IAuthorizationProvider authorizationProvider)
{
_authorizationProvider = authorizationProvider;
}
public void MyMethod()
{
// Getting the User information here is pretty simple
long userId = _authorizationProvider.GetUserId();
}
}
Normally I can get the user information from the HttpContext and from the session. So I wrote a SessionAuthorizationProvider:
public class SessionAuthorizationProvider{
public long? GetUserId()
{
HttpContext.Current?.Session?[SessionKeys.User]?.Id;
}
public long? GteTenantId() { ... }
}
But now I have a new method in the SignalR hub that use the same mechanism.
[HubName("myHub")]
public class MyHub : Hub
{
private IMyManager _myManager;
public MyHub(IMyManager myManager)
{
_myManager = myManager;
}
[HubMethodName("myHubMethod")]
public void MyHubMethod(long userId, long tenantId)
{
_myManager.MyMethod();
}
}
The problem is that a SignalR request doesn't have a session. Therefore I have also set the required user information in the hub method as parameters postet from the client.
So I thought it is the best solution for this problem to write a new AuthorizationProvider for SignalR and adapt the depdendency resolver. But I can't get the current user in the new SignalrAuthorizationProvider.
public class SignalrAuthorizationProvider{
public long? GetUserId()
{
// How to get the user information here???
}
public long? GteTenantId() { /* and here??? */ }
}
Is there a recommended solution to this problem?
Of course, I can extend MyMethod to accept the user information as a parameter. But MyMethod calls another method from another manager and that manager also calls another method. The user information is only needed for the last method call. So I had to change at least 3 methods and many more in the future.
Here is a sketch of the problem
This is a potential solution. But it's very bad
Session is not supported by SignalR by default and you should avoid using it. See No access to the Session information through SignalR Hub. Is my design is wrong?. But you still can use cookie or querystring to get the desired value.
In both case you need to have access to the HubCallerContext of the underlying hub, the one that is accessible through the Context property of the Hub.
In a ideal word you should just have to had the dependency to the SignalAuthorizationProvider
ie :
public class SignalrAuthorizationProvider {
public SignalrAuthorizationProvider(HubCallerContext context){
this._context = context;
}
private readonly HubCallerContext _context;
public long? GetUserId() {
return this._context.Request.QueryString["UserId"]
}
}
But due to SignalR design it is not possible. Context property is assigned after construction of the Hub and AFAIK there is no way to change it.
Source code here : HubDispatcher.cs
One possible solution would be to inject a mutable dependency inside the Hub and alter the object in the OnConnected, OnReconnected methods.
public class SignalrAuthorizationProvider : IAuthorizationProvider
{
private Boolean _isInitialized;
private String _userId;
public String UserId
{
get
{
if (!_isInitialized)
{
throw new Exception("SignalR hack not initialized");
}
return this._userId;
}
}
public void OnConnected(HubCallerContext context)
{
this.Initialize(context);
}
public void OnReconnected(HubCallerContext context)
{
this.Initialize(context);
}
private void Initialize(HubCallerContext context) {
this._userId = context.QueryString["UserId"];
this._isInitialized = true;
}
}
and the Hub
public abstract class CustomHub : Hub
{
public CustomHub(IAuthorizationProvider authorizationProvider)
{
this._authorizationProvider = authorizationProvider;
}
private readonly IAuthorizationProvider _authorizationProvider;
public override Task OnConnected()
{
this._authorizationProvider.OnConnected(this.Context);
return base.OnConnected();
}
public override Task OnReconnected()
{
this._authorizationProvider.OnReconnected(this.Context);
return base.OnReconnected();
}
}
Having a mutable dependency is not the best design but I can't see any other way to have access to IRequest or HubCallerContext.
Instead of having an abstract Hub class which is not a perfect solution. You can change the RegisterHubs autofac method to use AOP with Castle.Core and let the interceptor calls the methods for you.

DbContext is Disposed When Using Autofac Dependency Injection on WebApi project

I have a WebApi project using Entity Framework 6.0, Autfac for DI and CQRS architecture. The problem I have that DbContext isn't disposing how it supposed to. The action I take:
I run two quick requests, e.g. send request from Postman to one endpoint, runtime stops on breakpoint in controller method, I send second request to another endpoint in different controller.
Resume Runtime
if the second request finished before the first one is done, the first one throws and error that dbcontext was disposed and it cannot run whatever it was supposed to do
Originally problem appeared when I posted and patched from frontend one after another.
It seems like lifetime scope is not really per-request. It seems like all dbcontexts are disposed on one of the request's end. The other one does not have anything to work with.
How is it configured?
Starting from the highest layer - controller:
public class UsersController : BaseController, IUsersApi
{
private readonly IUserService _userService;
public UsersController(IUserService userService, ILogging logging) : base(logging)
{
_userService = userService;
}
[HttpGet]
[Route("api/users")]
public IList<UserDto> GetUsers()
{
try
{
return _userService.GetAllUsers();
}
catch (Exception e)
{
_logger.Error(e);
_logger.Trace(e);
throw;
}
}
[HttpPatch]
[Route("api/users/")]
public IHttpActionResult EditUsers(ICollection<UserEditDto> model)
{
try
{
_userService.EditUsers(model);
return Ok();
}
catch (Exception e)
{
_logger.Error(e);
_logger.Trace(e);
return BadRequest("Error");
}
}
}
Service layer:
public class UserService : IUserService
{
private readonly IServiceTools _serviceTools;
private readonly IUserQuerier _userQuerier;
public UserService(IServiceTools serviceTools, IUserQuerier userQuerier)
{
_serviceTools = serviceTools;
_userQuerier = userQuerier;
}
public void EditUsers(ICollection<UserEditDto> model)
{
var mapper = _serviceTools.AutoMapperConfiguration.Configure().CreateMapper();
var userEditCommands = mapper.Map<ICollection<UserEditDto>, ICollection<EditUserCommand>>(model);
foreach (var command in userSaveCommands)
{
_serviceTools.CommandBus.SendCommand(command);
CacheHelper.Clear(command.Id.ToString());
}
}
public IList<UserDto> GetAllUsers()
{
var allUsers = _userQuerier.GetAllUsers();
var result = allUsers.Select(x => new UserDto()
{
...
}).ToList();
return result;
}
}
Service Tools interface where command bus sits:
public interface IServiceTools
{
ICommandBus CommandBus { get; }
IAutoMapperConfiguration AutoMapperConfiguration { get; }
IIdentityProvider IdentityProvider { get; }
}
public class ServiceTools : IServiceTools
{
public ServiceTools(ICommandBus commandBus, IAutoMapperConfiguration autoMapperConfiguration, IIdentityProvider identityProvider)
{
CommandBus = commandBus;
AutoMapperConfiguration = autoMapperConfiguration;
IdentityProvider = identityProvider;
}
public ICommandBus CommandBus { get; }
public IAutoMapperConfiguration AutoMapperConfiguration { get; }
public IIdentityProvider IdentityProvider { get; }
}
And whatever handler for command:
public class EditUserHandler : IHandleCommand<EditUserCommand>
{
private readonly ICommandsContext _commandsContext;
public SaveUserHandler(ICommandsContext commandsContext)
{
_commandsContext = commandsContext;
}
public void Handle(EditUserCommand command)
{
... using dbcontext here...
}
}
}
For DI I use Autofac, all resources are set to per-request lifetime, split into modules, e.g. module for data access
public class DataModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AppNameDbContext>().As<ICommandsContext>().InstancePerRequest();
builder.RegisterType<AppNameDbContext>().As<IQueryContext>().InstancePerRequest();
base.Load(builder);
}
}
The difference between both interfaces is that IQueryContext cannot change entity states and use SaveChagnes() method. IQueryContext have all DbSets in it, while ICommandsContext inherits from it and adds SettingState methods (added, modified, deleted) and SaveChanges() method.
IQueryContext is injected into queries and ICommandsContext into commands as seend in example aboove.
Now the Autofac config for command bus looks like that:
public class InfrastractureModule : Module
{
private ICommandsContext _commandsContext;
private ITranslationsCommandsContext _translationsCommandsContext;
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AutoMapperConfiguration>().
As<IAutoMapperConfiguration>().InstancePerRequest();
builder.RegisterType<ServiceTools>().As<IServiceTools>().InstancePerRequest();
builder.Register(c =>
{
_commandsContext = c.Resolve<ICommandsContext>();
_translationsCommandsContext = c.Resolve<ITranslationsCommandsContext>();
return new CommandBus(CreateHandlersFactory);
})
.As<ICommandBus>().InstancePerRequest();
base.Load(builder);
}
private IHandleCommand CreateHandlersFactory(Type type)
{
if (type == typeof(XXXCommand))
{
return new XXXHandler(_commandsContext);
}
}
While the command bus looks like that
public class CommandBus : ICommandBus
{
private readonly Func<Type, IHandleCommand> _handlersFactory;
public CommandBus(Func<Type, IHandleCommand> handlersFactory)
{
_handlersFactory = handlersFactory;
}
public void SendCommand<T>(T command) where T : ICommand
{
var handler = (IHandleCommand<T>) _handlersFactory(typeof(T));
handler.Handle(command);
}
}
There is completely separate context used for translations for the app, but I do not thing that is important here.
I did not find any posts with similar problem. It only occurs when where two requests processed at the same time. I do not know if the configuration is wrong or Autofac messes things up, because it should not technically dispose dbcontext which was allocated for another request.
Sorry for the wall of text ;) I hope someone can help with that.
Obiously changing dbcontext's lifetime to SingleInstance fixed the problem, but we do not want that :)
SOLUTION EDIT:
As #ZeljkoVujaklija noticed CommandsDbContext declarations in InfrastractureModule seemed strange. I removed whole CommandBus registration from InfrastractureModule. Instead I created CommandsModule in the assembly where all the commands sit. It looks like that:
public class CommandsModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(x => x.IsAssignableTo<IHandleCommand>())
.AsImplementedInterfaces();
builder.Register<Func<Type, IHandleCommand>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(IHandleCommand<>).MakeGenericType(t);
return (IHandleCommand)ctx.Resolve(handlerType);
};
});
builder.RegisterType<CommandBus>()
.AsImplementedInterfaces();
}
}
Not only it fixes the problem but also gets rid of huge factory.
If you are running within ASP.NET Core you should run InstancePerLifetimeScope instead of InstancePerRequest
Use InstancePerLifetimeScope instead of InstancePerRequest. In previous ASP.NET integration you could register a dependency as InstancePerRequest which would ensure only one instance of the dependency would be created per HTTP request. This worked because Autofac was in charge of setting up the per-request lifetime scope. With the introduction of Microsoft.Extensions.DependencyInjection, the creation of per-request and other child lifetime scopes is now part of the conforming container provided by the framework, so all child lifetime scopes are treated equally - there’s no special “request level scope” anymore. Instead of registering your dependencies InstancePerRequest, use InstancePerLifetimeScope and you should get the same behavior. Note if you are creating your own lifetime scopes during web requests, you will get a new instance in these child scopes.
http://autofaccn.readthedocs.io/en/latest/integration/aspnetcore.html#differences-from-asp-net-classic

WebAPI self-hosting: How to communicate with host?

I'm self-hosting WebAPI on a Windows service with the goal of being able to communicate with the Windows service.
However, although I'm able to connect to my web service with no difficulty at a basic level, I'm very unclear on the relationship between the web service and it's host. If my ultimate goal is to expose information from the Windows service through the Web service, how can I share information and communicate between them? What does the web service code have access to that's in the windows service code?
EDIT: Hmmm, too broad... how to narrow this down?
Here is my code. What I want to do is to call "api/strings/0" and have it return "One". However, the List indexOfStrings lives in the Windows Service host. How does the web service controller access the information?
public class StringsController : ApiController
{
/// <summary>
/// Get one entry from indexOfStrings
/// </summary>
public string Get(int listIndex)
{
// How to return indexOfStrings[listIndex]?
return "";
}
}
public class TestWindowsService : ServiceBase
{
public const string ServiceAddress = "Address and port number";
private HttpSelfHostServer _server; // This is the server you're hosting WebAPI on
private HttpSelfHostConfiguration _config; // WebAPI config
private List<string> indexOfStrings = new List<string>();
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
TestWindowsService service = new TestWindowsService() { AutoLog = false };
ServiceBase.Run(service);
}
public TestWindowsService()
{
indexOfStrings.Add("One");
indexOfStrings.Add("Two");
indexOfStrings.Add("Three");
//Create a host configuration
_config = new HttpSelfHostConfiguration(ServiceAddress);
//Setup the routes
_config.Routes.MapHttpRoute(
name: "DefaultGetApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
// Create the server
_server = new HttpSelfHostServer(_config);
}
protected override void OnStart(string[] args)
{
_server.OpenAsync();
}
protected override void OnStop()
{
_server.CloseAsync().Wait();
_server.Dispose();
}
}
You can do this by plugging in a Dependency Injection container framework like Unity, Ninject, Autofac, Structure Map, etc and registering a service in the container and then injecting that service into your controller. There are Nuget packages for most of these DI frameworks to support Web API.
There is an example using Autofac here
However, using the same basic principle you can expose a service level object to controllers methods without using a DI Framework.
The idea is that you use a MessageHandler to insert your object instances to the Request Properties collection and then in the controller method pull it back out.
public class MyServiceHandler : DelegatingHandler
{
private readonly MyService _service;
public MyServiceHandler(MyService service)
{
_service = service;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Properties["MyService_Key"] = _service;
return base.SendAsync(request, cancellationToken);
}
}
In your configuration code you can add your message handler to the pipeline using,
config.MessageHandlers.Add(new MyServiceHandler(new MyService()));
and in your controller you can access the service like this,
public class StringsController : ApiController
{
/// <summary>
/// Get one entry from indexOfStrings
/// </summary>
public string Get(int listIndex)
{
var myService = Request.Properties["MyService_Key"] as MyService;
// How to return indexOfStrings[listIndex]?
var mystring = myService.GetMyString(99);
return "";
}
}
Ideally you should wrap up the access to your service in a helper method or a ApiController extension method, but those are just cosmetic details.
Now, you need to be careful, because MyService can now be called simultaneously on different threads. You need to ensure that you either use Concurrent collections for storing data or you use locks where necessary.

Categories