ServiceStack's Funq & ElasticSearch - elasticsearch

I am trying to wire up ElasticClient using ServiceStack's Funq, but I am getting a null reference exception when trying to call it.
Here is my set up:
In AppHost.cs:
var elasticSettings = new ConnectionSettings(new Uri("http://localhost:9200"), "listings");
var elasticClient = new ElasticClient(elasticSettings);
container.Register(elasticClient);
Then in my ServiceInterface project, in the ListingServices.cs class:
private ElasticClient Elastic; // also tried IElasticClient Elastic;
public object Post(CreateListing request)
{
Listing newAd = new Listing();
newAd = request.ConvertTo<Listing>();
using (IDbConnection db = DbFactory.Open())
{
db.Save(newAd);
Elastic.Index(newAd); // NULL REFERENCE EXCEPTION
}
return new CreateListingResponse { Result = true };
}
However Elastic is still set to Null & gives a null reference exception.
ANy ideas on how to resolve.

Property injection only works for public properties, so change the private field to:
public ElasticClient Elastic { get; set; }
Otherwise for private fields you need to instead use constructor injection.

Related

How to work with an DevArt edml file and start a connection?

I am working with the newest DevArt Oracle version and created a EDML file that connects to my Oracle 12 database and get the models with the db first approach.
I followed this howto:
https://www.devart.com/entitydeveloper/docs/
So I have my context and my model auto generated:
public partial class KiddataAdminEntities : DbContext
{
#region Constructors
/// <summary>
/// Initialize a new KiddataAdminEntities object.
/// </summary>
public KiddataAdminEntities() :
base(#"name=KiddataAdminEntitiesConnectionString")
{
Configure();
}
/// <summary>
/// Initializes a new KiddataAdminEntities object using the connection string found in the 'KiddataAdminEntities' section of the application configuration file.
/// </summary>
public KiddataAdminEntities(string nameOrConnectionString) :
base(nameOrConnectionString)
{
Configure();
}
private void Configure()
{
this.Configuration.AutoDetectChangesEnabled = true;
this.Configuration.LazyLoadingEnabled = true;
this.Configuration.ProxyCreationEnabled = true;
this.Configuration.ValidateOnSaveEnabled = true;
}
#endregion
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Anrede> Anrede { get; set; }
}
Now I try to get it to work in my main in another project (just a simple console application with a start.cs):
KiddataAdminEntities context = new KiddataAdminEntities("User Id=xxxx;Password=xxxx;Server=xx;Direct=True;Sid=xxxx;Persist Security Info=True");
var listOfAnrede = context.Anrede.ToList();
So now I get the error "Keyword user id not supported".
I googled this and I found out that problably EF6 is trying to get a default connection, not an oracle connection with DevArt...
I tried to play with the app.config in different ways but it didnt help.
Now I tried to create my own connection with the DevArt.Data.Oracle provider, like shown here:
https://www.devart.com/dotconnect/oracle/articles/tutorial-connection.html
OracleConnection oc = new OracleConnection();
oc.ConnectionString = constring2;
oc.Open();
var test = oc.ServerVersion;
This works fine, so the connectionstring is okay, but still I can't put these two together. I tried to overload the constructor so I can put in my Connection:
public KiddataAdminEntities(DbConnection con, bool contextOwnsConnection)
: base(con, contextOwnsConnection)
{
}
Then I got the error on
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
That I should not do that...
If you are using XML mapping with Devart Entity Model (*.edml), try this code:
using Devart.Data.Oracle;
using System.Data.EntityClient;
...
OracleConnectionStringBuilder oracleBuilder = new OracleConnectionStringBuilder();
oracleBuilder.UserId = "...";
oracleBuilder.Password = "...";
oracleBuilder.Server = "...";
oracleBuilder.Direct = true;
oracleBuilder.Sid = "...";
oracleBuilder.PersistSecurityInfo = true;
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.Provider = "Devart.Data.Oracle";
entityBuilder.ProviderConnectionString = oracleBuilder.ConnectionString;
entityBuilder.Metadata = #"res://*/MyModel.csdl|res://*/MyModel.ssdl|res://*/MyModel.msl";
using (Entities context = new Entities(entityBuilder.ToString())) {
var a = context.MyEntity.First();
}
Refer to
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/how-to-build-an-entityconnection-connection-string
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/connection-strings
FYI, you can generate fluent mapping (instead of XML mapping). For this, disable a predefined EntityObject template, enable the DbContext template and set the options:
Fluent Mapping=True in the properties of DbContext template
Metadata Artifact Processing=Do Not Generate Mapping Files in the properties of EntityContextModel

Xamarin Forms with WorkManger

I am trying to use the Xamarin implementation of WorkManager, in the nuget package Xamarin.Android.Arch.Work.Runtime.
The questions is: how to pass "complex" parameters to the worker class?
I have a Xamarin Forms application with DI and others classes, but the job only receives a Java.Lang.Object.
My code:
// Method to Schedule the Job
// See the dataParam? That line throw an exception
// I can manage to pass a simple string or int to the job this way, but not
// complex classes
public void ScheduleAppJobs(IContainerProvider containerRegistry)
{
//here the code throw an exception
var dataParam = new Data.Builder().Put("param", new JobParameter());
var syncWorkerReuest = PeriodicWorkRequest.Builder.From<SyncChecklistWorker>(TimeSpan.FromMinutes(5))
.SetInputData(dataParam.Build())
.Build();
WorkManager.Instance.Enqueue(syncWorkerReuest);
}
//this was my try to create a custom class and populate with my objects
//But didn't worked
public class JobParameter : Java.Lang.Object
{
}
//my job implementation
public class SyncChecklistWorker : Worker
{
public SyncChecklistWorker(Context context, WorkerParameters workerParameters) : base(context, workerParameters)
{
}
public override Result DoWork()
{
if (InputData.KeyValueMap.TryGetValue("param", out Java.Lang.Object #object))
{
var jobParam = (JobParameter)#object;
// here I would like to get my DI container to resolve services and execute business logic
// var diResolver = jobParam.GetDIContainer();
return Result.InvokeSuccess();
}
return Result.InvokeRetry();
}
}
}
The problem is:
The only way to pass input data to a jobs the Data.Builder only accepts Java.Lang.Object. Even trying to approach of having JobParameter : Java.Lang.Object I get the following error when trying to execute the: new Data.Builder().Put("param", new JobParameter()); Error: Java.Lang.IllegalArgumentException: 'Key param has invalid type class crc648d221dddf00bc7fb.JobParameter'
On the official Microsoft Docs the FireBase Job Dispatcher nuget is deprecated. So how to work with the new WorkManager one?
FireBase Job Dispatcher Doc:
https://learn.microsoft.com/en-us/xamarin/android/platform/firebase-job-dispatcher
Deprecated nuget:
https://www.nuget.org/packages/Xamarin.Firebase.JobDispatcher
Any idea of how to solve this?
Work request from Data builder accepts only the premitive types. You can pass the object by serializing to JSON string format and in DoWork() you can deserialize it.
public void ScheduleAppJobs(IContainerProvider containerRegistry)
{
var dataParam = new Data.Builder().PutString("param",serializeToJson(new
MyClass()));
var syncWorkerReuest = PeriodicWorkRequest.Builder.From<SyncChecklistWorker>
(TimeSpan.FromMinutes(5))
.SetInputData(dataParam.Build())
.Build();
WorkManager.Instance.Enqueue(syncWorkerReuest);
}
public override Result DoWork()
{
var jsonString = InputData.GetString("param");
var myClassObj = deserializeFromJson(jsonString );
}
using Newtonsoft.Json;
public string serializeToJson(MyClass myClassObj)
{
var resultString = JsonConvert.SerializeObject(myClassObj);
return resultString;
}
// Deserialize to single object.
public MyClass deserializeFromJson(string jsonString)
{
var serializer = new JsonSerializer();
var resultObject = serializer.Deserialize<MyClass>(jsonString);
}

Get a specific service implementation based on a parameter

In my Sling app I have data presenting documents, with pages, and content nodes. We mostly server those documents as HTML, but now I would like to have a servlet to serve these documents as PDF and PPT.
Basically, I thought about implementing the factory pattern : in my servlet, dependending on the extension of the request (pdf or ppt), I would get from a DocumentBuilderFactory, the proper DocumentBuilder implementation, either PdfDocumentBuilder or PptDocumentBuilder.
So first I had this:
public class PlanExportBuilderFactory {
public PlanExportBuilder getBuilder(String type) {
PlanExportBuilder builder = null;
switch (type) {
case "pdf":
builder = new PdfPlanExportBuilder();
break;
default:
logger.error("Unsupported plan export builder, type: " + type);
}
return builder;
}
}
In the servlet:
#Component(metatype = false)
#Service(Servlet.class)
#Properties({
#Property(name = "sling.servlet.resourceTypes", value = "myApp/document"),
#Property(name = "sling.servlet.extensions", value = { "ppt", "pdf" }),
#Property(name = "sling.servlet.methods", value = "GET")
})
public class PlanExportServlet extends SlingSafeMethodsServlet {
#Reference
PlanExportBuilderFactory builderFactory;
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
Resource resource = request.getResource();
PlanExportBuilder builder = builderFactory.getBuilder(request.getRequestPathInfo().getExtension());
}
}
But the problem is that in the builder I would like to reference other services to access Sling resources, and with this solution, they're not bound.
I looked at Services Factory with OSGi but from what I've understood, you use them to configure differently the same implementation of a service.
Then I found that you can get a specific implementation by naming it, or use a property and a filter.
So I've ended up with this:
public class PlanExportBuilderFactory {
#Reference(target = "(builderType=pdf)")
PlanExportBuilder pdfPlanExportBuilder;
public PlanExportBuilder getBuilder(String type) {
PlanExportBuilder builder = null;
switch (type) {
case "pdf":
return pdfPlanExportBuilder;
default:
logger.error("Unsupported plan export builder, type: " + type);
}
return builder;
}
}
The builder defining a "builderType" property :
// AbstractPlanExportBuilder implements PlanExportBuilder interface
#Component
#Service(value=PlanExportBuilder.class)
public class PdfPlanExportBuilder extends AbstractPlanExportBuilder {
#Property(name="builderType", value="pdf")
public PdfPlanExportBuilder() {
planDocument = new PdfPlanDocument();
}
}
I would like to know if it's a good way to retrieve my PDF builder implementation regarding OSGi good practices.
EDIT 1
From Peter's answer I've tried to add multiple references but with Felix it doesn't seem to work:
#Reference(name = "planExportBuilder", cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
private Map<String, PlanExportBuilder> builders = new ConcurrentHashMap<String, PlanExportBuilder>();
protected final void bindPlanExportBuilder(PlanExportBuilder b, Map<String, Object> props) {
final String type = PropertiesUtil.toString(props.get("type"), null);
if (type != null) {
this.builders.put((String) props.get("type"), b);
}
}
protected final void unbindPlanExportBuilder(final PlanExportBuilder b, Map<String, Object> props) {
final String type = PropertiesUtil.toString(props.get("type"), null);
if (type != null) {
this.builders.remove(type);
}
}
I get these errors :
#Reference(builders) : Missing method bind for reference planExportBuilder
#Reference(builders) : Something went wrong: false - true - MANDATORY_MULTIPLE
#Reference(builders) : Missing method unbind for reference planExportBuilder
The Felix documentation here http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html#reference says for the bind method:
The default value is the name created by appending the reference name to the string bind. The method must be declared public or protected and take single argument which is declared with the service interface type
So according to this, I understand it cannot work with Felix, as I'm trying to pass two arguments. However, I found an example here that seems to match what you've suggested but I cannot make it work: https://github.com/Adobe-Consulting-Services/acs-aem-samples/blob/master/bundle/src/main/java/com/adobe/acs/samples/services/impl/SampleMultiReferenceServiceImpl.java
EDIT 2
Just had to move the reference above the class to make it work:
#References({
#Reference(
name = "planExportBuilder",
referenceInterface = PlanExportBuilder.class,
policy = ReferencePolicy.DYNAMIC,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
})
public class PlanExportServlet extends SlingSafeMethodsServlet {
Factories are evil :-) Main reason is of course the yucky class loading hacks that are usually used but also because they tend to have global knowledge. In general, you want to be able to add a bundle with a new DocumentBuilder and then that type should become available.
A more OSGi oriented solution is therefore to use service properties. This could look like:
#Component( property=HTTP_WHITEBOARD_FILTER_REGEX+"=/as")
public class DocumentServlet {
final Map<String,DocBuilder> builders = new ConcurrentHashMap<>();
public void doGet( HttpServletRequest rq, HttpServletResponse rsp )
throws IOException, ServletException {
InputStream in = getInputStream( rq.getPathInfo() );
if ( in == null )
....
String type = toType( rq.getPathInfo(), rq.getParameter("type") );
DocBuilder docbuilder = builders.get( type );
if ( docbuilder == null)
....
docbuilder.convert( type, in, rsp.getOutputStream() );
}
#Reference( cardinality=MULTIPLE, policy=DYNAMIC )
void addDocBuilder( DocBuilder db, Map<String,Object> props ) {
docbuilders.put(props.get("type"), db );
}
void removeDocBuilder(Map<String,Object> props ) {
docbuilders.remove(props.get("type"));
}
}
A DocBuilder could look like:
#Component( property = "type=ppt-pdf" )
public class PowerPointToPdf implements DocBuilder {
...
}

Asp.net Identity, Generate WebApi token OAuthGrantResourceOwnerCredentialsContext - no access to UserManager using Unity

I am trying to setup a project structure so that I have a WebApi, WebUI and Domain layer. I have moved all the Asp.Net.Identity objects into the Domain layer and have also setup the ApplicationContext here too (inheriting from IdentityContext).
(I have used this tutorial and package as a base which is excellent. http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration/)
In the WebAPI layer I am able to use the Account controller correctly to login and register. However, I cannot generate an access token.
The OAuthGrantResourceOwnerCredentialsContext method internally uses
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
This works fine but doesnt give me the same context as my Account Controller as I am using Unity constructor injection in this to use my ApplicationUserManager from the domain.
I have tried injecting the OAuth class but I never seem to get the instance back.
Any advice?
Edit, this is what I have in Startup class in a default WebApi project.
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
So the ApplicationOAuthProvider seems to be used when getting an access token.
--
More info.
UnityConfig.cs
container.RegisterType<ApplicationDbContext>(); //this is referencing my domain layer
Startup.Auth.cs
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
ApplicationOAuthProvider.cs
Have injected constructor as below
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
private ApplicationUserManager userManager;
public ApplicationOAuthProvider(ApplicationUserManager userManager)
{
this.userManager = userManager;
}
public ApplicationOAuthProvider(string publicClientId)
{
//this.userManager = userManager;
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); //PROBLEM LINE!!!
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
}
}
The problem line is shown above. This method gets called when requesting a token, and the userManager is always null.
Edit to show UnityWebApiActivator.cs
public static class UnityWebApiActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
// Use UnityHierarchicalDependencyResolver if you want to use a new child container for each IHttpController resolution.
// var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());
var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
I have just create pure WebApi project with Identity, checked over the classes and not sure I understand your question correctly.
The standard VS2013 template contains this in Startup.Auth.cs:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// blah - other stuff
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
Provider = new ApplicationOAuthProvider(PublicClientId),
// another blah
};
app.UseOAuthBearerTokens(OAuthOptions);
//blah-blah-blah
}
}
I have checked and ApplicationOAuthProvider is not used anywhere else. So no need to inject it.
Inside of this class, as you say, it calls for context.OwinContext.GetUserManager<ApplicationUserManager>() to get user manager. If you get an incorrect instance of ApplicationDbContext there, then you inject incorrect instance of ApplicationUserManager into Owin context. Do you still have a line with this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Go replace it with this:
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
This should do the job - would be the best solution.
Alternatively in ApplicationOAuthProvider replace line where you get the ApplicationUserManager from OWIN context with this:
var userManager = DependencyResolver.Current.GetService<ApplicationUserManager>()
This should resolve your user manager from Unity, giving you correct DbContext.

Autofac, Owin, Webapi and injecting to AuthorizationServerProvider

After reading questions and articles about using autofac with owin and webapi, I came across a solution to inject services but it does not work. Here is my code:
public class StartUp
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
var builder = new ContainerBuilder(); // Create the container builder.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); // Register the Web API controllers.
var authcontext = new AuthContext();
builder.RegisterInstance(authcontext).AsSelf().SingleInstance();
//Updated
//var simpleauth = new SimpleAuthorizationServerProvider();
//Updated
// builder.RegisterInstance(simpleauth).SingleInstance().AsSelf().PropertiesAutowired();
builder.Register(x => new UserStore<IdentityUser>(authcontext)).As<IUserStore<IdentityUser>>();
//updated
builder.Register(x =>
{
var p = new SimpleAuthorizationServerProvider();
var userStore = x.Resolve<IUserStore<IdentityUser>>();
p.userManager = new UserManager<IdentityUser>(userStore);
return p;
}).AsSelf().PropertiesAutowired();
builder.RegisterType<AuthRepository>().As<IAuthRepository>().InstancePerRequest().PropertiesAutowired();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container); // Create an assign a dependency resolver for Web API to use.
config.DependencyResolver = resolver;
app.UseAutofacMiddleware(container);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
ConfigureOAuth(app, resolver);
}
public void ConfigureOAuth(IAppBuilder app, AutofacWebApiDependencyResolver resolver)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
//updated
Provider = new SimpleAuthorizationServerProvider()
//resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
But in SimpleAuthorizationServerProvider class, when a method like ValidateClientAuthentication is begin called, all the services are null, here is the code:
public readonly IAuthRepository repository;
public readonly UserManager<IdentityUser> userManager;
public readonly AuthContext dbContext;
public SimpleAuthorizationServerProvider()
{
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId;
string clientSecret;
if (context.TryGetFormCredentials(out clientId, out clientSecret))
{
try
{
Client client = await repository.FindClientById(clientId);
}
}
}
Would you help me please ?
Updated
If in ConfigureOAuth method I use the following approach:
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
};
I get error:
An exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll but was not handled in user code
Additional information: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
When you register an instance of an object rather than a type, even if you specify PropertiesAutowired that will not take effect because Autofac assumes you've done all the work you want when you create the instance. If you want properties wired in, you need to do that in an OnActivated handler.
There are actually a lot of things at play in this sample code that will not work.
The values in SimpleAuthorizationServerProvider are fields not properties so PropertiesAutowired won't work on them.
The fields are marked readonly and they're never set.
You have UserManager<IdentityUser> registered as a lambda but also have PropertiesAutowired which won't work - you can only use PropertiesAutowired on a reflection-based component (e.g., RegisterType<T>).
Consider registering a lambda for your provider and set everything in the lambda:
builder.Register(c => {
var p = new SimpleAuthorizationServerProvider();
p.repository = c.Resolve<UserManager<IdentityUser>>();
// ...and so on
return p;
}).AsSelf().SingleInstance();
Also, keep in mind that if you register an instance (or register something as SingleInstance the properties will be resolved one time and that's it. So if you have some dependencies that are InstancePerDependency or InstancePerRequest, that's not going to work the way you think - they'll be resolved one time and effectively be singletons after that.
Update 1
Based on the original and updated code, it occurs to me that it would be good if you could check out some of the Autofac doc to understand better how it works. For example, the use of fields in SimpleAuthorizationServerProvider shows you may not totally get how injection works in Autofac or how to properly register things so Autofac can do the work for you.
Registration concepts
Web API integration
Working with per-request lifetime
For example, looking at the updates...
You now have a lambda registered for the SimpleAuthorizationServerProvider but I don't see where you set the repository field there.
You don't need PropertiesAutowired on the SimpleAuthorizationServerProvider registration because you're registering a lambda and the properties will not be autowired (as noted earlier).
The only component I see as being registered InstancePerRequest is the AuthRepository but, like I said, I don't see where that's being resolved or set - and that's the only thing that would generate the exception you noted. There is an FAQ on dealing with that exact exception that you should look into.
Also, you are showing two different versions of the OAuthServerOptions being initialized and it's hard to tell which one is "real."
I would recommend a fairly major refactoring to enable things to actually use DI correctly.
Change the SimpleAuthorizationServerProvider to stop using public fields and add them as constructor parameters so Autofac can wire the stuff up for you.
public class SimpleAuthorizationServerProvider
{
public IAuthRepository Repository { get; private set; }
public UserManager<IdentityUser> UserManager {get; private set; }
public AuthContext Context { get; private set; }
public SimpleAuthorizationServerProvider(
IAuthRepository repository,
UserManager<IdentityUser> userManager,
AuthContext context)
{
this.Repository = repository;
this.UserManager = userManager;
this.AuthContext = context;
}
}
During startup, fix your registrations to remove extraneous stuff and take advantage of the Autofac auto-wiring goodness.
public class StartUp
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config);
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Register the auth context instance but skip
// the extra .AsSelf() and .SingleInstance() because
// it's implicit.
builder.RegisterInstance(new AuthContext());
// Use the lambda to resolve the auth context rather
// than making a closure over an instance.
builder.Register(c => new UserStore<IdentityUser>(c.Resolve<AuthContext>()))
.As<IUserStore<IdentityUser>>();
// Just register the provider type and let Autofac
// do the work without all this manual stuff. Skip
// the .AsSelf() because it's implicit if you don't
// specify other interfaces and don't auto-wire properties
// because you don't need it.
builder.RegisterType<SimpleAuthorizationProvider>();
// This is fine, but I can't tell where it's used - if
// you are using it at app startup or OUTSIDE a request,
// you will get that exception you noted. Also, unless
// you're actually using property injection, lose the
// .PropertiesAutowired() call.
builder.RegisterType<AuthRepository>()
.As<IAuthRepository>()
.InstancePerRequest()
.PropertiesAutowired();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
app.UseAutofacMiddleware(container);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
ConfigureOAuth(app, resolver);
}
public void ConfigureOAuth(IAppBuilder app, AutofacWebApiDependencyResolver resolver)
{
var options = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
// If you want the values to be wired up, you have
// to do a resolve. Note, however, that since you're
// doing this wire-up at app startup, there's no request
// scope, so if something in here is registered `InstancePerRequest`
// you will get an exception.
Provider = resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
};
app.UseOAuthAuthorizationServer(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
Under the assumption that's all the code you should be OK. If things aren't set - like one of the SimpleAuthorizationServerProvider properties comes through as null, or if you get an exception because it's missing a dependency, or if you get the exception about there being no request scope... then there's something else going on that you haven't put in your question.
Again, please take the time to check out the docs and familiarize yourself with Autofac. I think many of the troubles you're running into are the result of some misunderstanding on how things get wired up.

Resources