Autofac Web Api Get current scope - asp.net-web-api

I have the following extension method:
public static SessionUserInfo ToSessionUserInfo(this Customer customer)
{
//Some logic here which need some services
}
I'm using autofac with web api and owin, but because this is an extension method i cannot use Constructor injection. So i need to resolve the services from the logic in the code.
Normally using MVC and Autofac.Integration.MVC I would do something like that:
var scope = AutofacDependencyResolver.Current.RequestLifetimeScope;
MyService service = scope.Resolve<MyService>();
But I could not find a way to accomplish the same with Web API.
How can I do this in Web Api?

Unless you are using OWIN in your API, you should have your Autofac configuration setup in your WebAPI like this, which is the standard way to configure Autofac for WebApi.
Include nuget pacakge Autofac.Integration.WebApi
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<MyType>();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
Should you need to request the LifetimeScope like in your example, you can then request this from GlobalConfiguration.
var scope = GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope();
MyService service = scope.Resolve<MyService>();
Autofac WebApi configuration reference

Related

Masstranist - Access properties from middleware

I use Masstransit in multi-tenant application. On Web Api part I use Owin middleware to resolve tenant ID from DNS. I can access it globaly from services using OWIN environment.
I've created a Masstransit middleware to intecept the message and get tenant ID. In some cases I need to access it.
Since the bus is singleton-scoped, how can I access it?
I tried with IConsumeObserver.PreConsume, in debug I see private properties from the consumer, but I can't access them.
UPDATE:
Each message has TenantId property. We use Entity Framework global filter to filter all queries by TenantId. It is set on Unit of Work that we inject into consumer:
public class MyConsumer : IConsumer<IMyCommand>
{
private readonly ITenantConfiguration _tenantConfiguration;
private readonly IUnitOfWork _uow;
public MyConsumer(ITenantConfiguration tenantConfiguration, IUnitOfWork uow)
{
_tenantConfiguration = tenantConfiguration;
_uow = uow;
}
public Task Consume(ConsumeContext<IMyCommand> context)
{
return Task.FromResult(true);
}
}
The problem is that Unit of work is instantiated before I get TenantId from the message. I use Ninject and if I set unit of work to .InTransientScope() it solves my problems.
If I use Web Api, I get tenantId from Owin Middleware startup class:
var domain = context.Request.Host.Value.ToLower();
context.Set<object>("tenantId", tenantId);
Later, I can access it from services:
var owinContext = HttpContext.Current.Request.GetOwinContext();
var owinEnvVars = owinContext.Environment;
var currentTenantInfo = owinEnvVars["tenantId"]
Is it possible to have something like that when Masstransit messages?

Managing AutoFac object creation for UnitOfWork

I am new to architecture, I am in the process of learning and designing an application end to end. I have the below architecture and am using Autofac to manage object creation.
All businessobject contracts have been setup on webapi startup and that is the only startup which can actually startup all my autofac configurations/modules.
I use UnitOfWork/Repository pattern and it resides beyond my business layer, I do not want to refer the UnitOfWork in my WebAPi but i cannot startup UnitOfWork otherwise.
Can someone please give me some inputs on what should be my architecture/design/autofac unitofwork implementation?
In App_start register web project specific dependencies (controllers, etc). Have a static method in BL layer which registers unit of work, repositories, etc. Call this static method in App_start when all the web dependencies are being registered as below:
//App_Start (web project)
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
MyProject.BusinessLayer.RegisterDependancies.Register(builder); <-- Register Unit of Work here in static BL method
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
builder.RegisterModule<AutofacWebTypesModule>();
builder.RegisterWebApiFilterProvider(config);
builder.RegisterModule(new AutofacModules.AutoMapperModule());
builder.RegisterModule(new AutofacModules.Log4NetModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
//Static method in BL
namespace MyProject.BusinessLayer
{
public static class RegisterDependancies
{
public static void Register(ContainerBuilder builder)
{
builder.RegisterType<MyContext>().As<IDataContextAsync>().InstancePerLifetimeScope();
builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepositoryAsync<>)).InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(BusinessService).Assembly).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
}
}
}

Is GlobalConfiguration in System.Web.Http.WebHost compatible with Owin?

I'm currently moving a WebApi 1 to a WebApi 2 project with OWIN.
In this piece of code GlobalConfiguration is in System.Web.Http.WebHost.
public class HandlerErrorFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var logFactory = GlobalConfiguration.Configuration.DependencyResolver
.GetService(typeof(ILoggerFactory)) as ILoggerFactory;
...
}
}
I think this is not Owin compatible, but I can't find how to rewrite this so I can access the dependency resolver.
I am not entirely clear about your question here...but GlobalConfiguration is comaptible with Owin middleware...There is also something called System.Web.Http.Owin which is an Web API Owin Adpater middleware...if you use this adapter then GlobalConfiguration must not be used...actually this is the same adapter which is used in case of Owin Selfhost scenario too...
if you are NOT using this adapter and just using other Owin middleware along with System.Web.Http.WebHost, then your above code should work just fine...are you seeing anything different?

Get Username of Currently interacting User in WCF both Rest Endpoint and MVC3 with Windows Authentication

In an MVC3 project that I'm working on we're trying to move a lot of our logic that is currently in the controllers into a service layer and expose it as a REST Service in WCF.
So in our Global.asax we create a Service Route like so:
RouteTable.Routes.Add(new ServiceRoute
("Exampleservice", new WebServiceHostFactory(), typeof(ExampleService)));
and our controllers access the service something like this:
public class ExampleController : Controller {
private IExampleService service;
public ExampleController() {
this.service = new ExampleService();
}
public ActionResult Index() {
var results = service.GetAll();
return View(results);
}
}
The main point here being that we use the service class directly (without making requests over the network with an HttpClient).
Our website uses Windows Authentication (it's an intranet site) and we would like to keep it that way. My Question is, is there a way that I can get the User's Identity in the service class that will work both for how we have the Controllers using the service, and the way that WCF uses the service?
For example:
[ServiceContract]
public interface IExampleService
{
[WebGet(UriTemplate = "/")]
List<Results> GetAll();
}
public class ExampleService : IExampleService
{
List<Results> GetAll() {
// Get User Name Here
// In ASP.Net I would use User.Identity.Name
// If I was just worrying about the the REST service I would use
// ServiceSecurityContext.Current.WindowsIdentity.Name
}
}
The instruction suggested by #Ryand.Johnson is correct. The point here is that the controller do not send any credentials to the web service because it run under the asp.net user indentity not the identity of the currently loggedd user. The only way to pass the identity to the proxy is by embedding the call to the web service within an impersonation context this way:
using (WindowsImpersonationContext impersonatedUser = (User.Identity as System.Security.Principal.WindowsIdentity).Impersonate()){
//your proxy call here }
If still this way you get null you have to set manually the default credentials to your proxy
Yes, in the service security context...
OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name

How to setup a DAL RESTful service with EFCodeFirst for MVC applications?

For an MVC3 application I want to create a reusable DAL that is accessed as a service, as this will be used for other projects in the future.
I created all the entities with TT templates and EFCodeFirst in a separate project, then consumed it in a RESTful WCF service.
The structure of this service seems a bit different from other WCF services I have written where I have specified RESTful signatures and optional JSON responses as method decorators in the service's interface, ie:
[WebGet(UriTemplate = "GetCollection")]
public List<SampleItem> GetCollection()
{
// TODO: Replace the current implementation to return a collection of SampleItem instances
return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Hello" } };
}
[WebInvoke(UriTemplate = "", Method = "POST")]
public SampleItem Create(SampleItem instance)
{
// TODO: Add the new instance of SampleItem to the collection
throw new NotImplementedException();
}
Where this RESTful WCF service (created from the RESTful WCF option) differs is that there is no interface, and I can decorate the service methods with what I need - that's fine. The service will expose methods like GetUserByID(int id), etc.
The issue is that I want to use this in a MVC3 application, and am not clear on how to hook up the models to my service and would like some direction in accomplishing this.
Thanks.
Assume you want to expose an entity called Person. The WCF REST service may look as follows:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public partial class PeopleWebService
{
[WebGet(UriTemplate = "")]
public List<Person> GetCollection()
{
try
{
IPeopleRepository repository = ServiceLocator.GetInstance<IPeopleRepository>();
var people = repository.GetPeople();
// use automapper to map entities to Person resource
var result = Mapper.Map<List<Person>>(people);
return result;
}
catch (Exception exception)
{
// do logging etc
throw new WebFaultException(HttpStatusCode.InternalError);
}
}
/* other methods */
}
These services can be generated by T4 too.
Notice that there is no need for an interface on the WCF service itself. I generally do not expose any database entities directly in WCF services as my services evolve differently than my database entities. Once an API is published it should pretty much remain the same. This prevents me from changing my database schema to fit new requirements.
Instead I map my entities to resources. So Person may looks as follows:
[DataContract]
public class Person
{
[DataMember]
public string GivenName { get; set; }
/ * more properties */
}
It may be a good thing to use T4 to generate these as well. Routing is defined something like this:
public void Register(RouteCollection routes)
{
routes.AddService<WorkspaceWebService>("api/v1/people");
}
To consume it from the ASP.NET MVC project, you can share your resources (aka Person) as defined above as an assembly, or you can use T4 to generate a separate set of resources that are almost the same, but with some additional attributes needed for ASP.NET MVC, like those used for validation. I would generate it, because my ASP.NET MVC view models generally evolve independently to my REST resources.
Lets assume your REST service runs at https://api.example.com/ and your MVC website is running at https://www.example.com/. Your PeopleController may look as follows.
public class PeopleController : ControllerBase
{
[HttpGet]
public ActionResult Index()
{
return View(Get<List<Person>>(new Uri("https://api.example.com/api/v1/people")));
}
protected T Get<T>(Uri uri)
{
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "text/xml";
using (var response = (HttpWebResponse) request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
Debug.Assert(responseStream != null, "responseStream != null");
var serializer = new DataContractSerializer(typeof (T));
return (T) serializer.ReadObject(responseStream);
}
}
}
}
From your question, I assume you want to use JSON. For that you just have to set the appropiate ContentType on the request and use the DataContractJsonSerializer rather than DataContractSeralizer. Note that there are some issues with dates and DataContractJsonSerializer. The WCF rest service will automatically return XML if the contenttype is "text/xml" and JSON if it is "application/json".
Notice that the MVC application has no knowledge of the database, the database entities or its database context. In fact there is no database logic in the MVC application. You will have to pay close attention to security, because the user context is missing from the WCF rest services. But, that is a whole different discussion.
The way to think about this is that your MVC app now only knows about your service. It has no clue that there's a DAL behind it. Basically, consider the service your "Persistence" layer. So, now your MVC model must populate itself using the service. So, just like any other application would populate a service, that is how your model will populate itself. Then your controllers will use your model return your views.
That wasn't the nitty gritty you may be looking for, but there are plenty of resources out there on how to consume RESTful services in .NET. Check those out and get those populating your model. Then get your model to your view.

Resources