Registering concrete type with parameter is null using Autofac - autofac

I have the following class:
public class Errors
{
private readonly string _connectionString;
public Errors(string connectionString)
{
_connectionString = connectionString;
}
}
I'm trying to register using Autofac like so:
builder.RegisterType<Errors>().WithParameter("connectionString", System.Configuration.ConfigurationManager.ConnectionStrings["myConn"].ConnectionString);
This object is getting injected into another object but it's always null. Looking further into the exception, the following error message is displayed:
Cannot choose between multiple constructors with equal length 1 on type 'System.String'.
Select the constructor explicitly, with the UsingConstructor() configuration method, when the component is registered.
I've tried registering using the UsingConstructor and WithParameter and there's no change.

Try This, there are 2 ways to register
First Type:
builder.Register(c => new Errors(System.Configuration.ConfigurationManager.ConnectionStrings["myConn"].ConnectionString)).InstancePerLifetimeScope();
Second Type:
public class Errors
{
private string _connectionString{ get; set; }
public Errors(string connectionString)
{
_connectionString = connectionString;
}
}
Register Like below
builder.RegisterType<Errors>().WithParameter("connectionString", System.Configuration.ConfigurationManager.ConnectionStrings["myConn"].ConnectionString);
EDIT: Testing
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.Register(c => new Errors(ConfigurationManager.ConnectionStrings["myConn"].ConnectionString)).InstancePerLifetimeScope(); // Type 1
// builder.RegisterType<Errors>().WithParameter("connectionString", ConfigurationManager.ConnectionStrings["myConn"].ConnectionString); // Type 2
var container = builder.Build();
var objErrors = container.Resolve<Errors>();
}
}
And the config file looks like
<connectionStrings>
<add name="myConn" connectionString="Some Connection String"/>
</connectionStrings>
Please read this Autofac Wiki
Tested in Autofac Version: 2.6.1.841
Result:

Related

Passing connection string to Entity framework at runt time for each call

My Entity framework context is as following
public partial class MyContext : DbContext, IMyContext
{
static MyContext()
{
System.Data.Entity.Database.SetInitializer<MyContext>(null);
}
public MyContext()
: base("Name=MyContext")
{
}
I am resolving it through autofac in the following way
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
This db context gets called in repository layer
#region Fields
private readonly IMyContext _context;
#endregion
#region Constructors and Destructors
public EmployeeRepository(IMyContext context)
{
_context = context;
}
#endregion
public void Create(Employee emp)
{
this._context.Employee.Add(emp);
}
Now my issue is , I want to set the connection string dynamically per call. The connection string will be passed through a webapi which i want to pass on to this context. Can anyone help me how can i do that? I am confused about autofac here. Secondly how can i make sure each call sets connection string and does not cache it.
You can use a factory that will build the context and set the connectionstring for you.
public interface IContextFactory
{
IContext GetInstance();
}
public class MyContextFactory : IContextFactory
{
public IContext GetInstance()
{
String connectionString = this.GetConnectionString(HttpContext.Current);
return new MyContext(connectionString);
}
private String GetConnectionString(HttpContext context)
{
// do what you want
}
}
builder.RegisterType<MyContextFactory>()
.As<IContextFactory>()
.InstancePerRequest();
builder.Register(c => c.Resolve<IContextFactory>().GetInstance())
.As<IContext>()
.InstancePerRequest();
If you can't get connectionstring based on HttpContext, you can change contextFactory implementation to expect initialization by WebAPI before creating the instance. For example :
public interface IContextFactory
{
IContext GetInstance();
void Initialize(String connectionString);
}
public class MyContextFactory : IContextFactory
{
private String _connectionString;
public void Initialize(String connectionString)
{
this._connectionString = connectionString;
}
public IContext GetInstance()
{
if (this._connectionString == null)
{
throw new Exception("connectionString not initialized");
}
return new MyContext(this._connectionString);
}
}
At the beginning of your web API call (through attribute for example), you can call the Initialize method. Because the factory is InstancePerRequest you will have one instance for the duration of the request.
By the way, I'm not sure to understand this registration
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
It looks buggy because you will have 2 different registration of the same type and not for the same scope, is it intended ? Furthermore, it doesn't sound a good idea to register a DbContext, do you need this registration ?
The following registration looks better :
builder.RegisterType<MainContext>()
.As<IMainContext>()
.As<DbContext>()
.InstancePerRequest();

dapper with autofac and repository pattern

I am using dapper with the repository pattern in a WebApi Application and I have the following problem.
The Repository Class is as follows
public class Repository : DataConnection, IRepository
{
public Repository(IDbConnection connection)
: base(connection)
{
}
public T GetFirst<T>(object filters) where T : new()
{
//Creates the sql generator
var sqlGenerator = new MicroOrm.Pocos.SqlGenerator.SqlGenerator<T>();
//Creates the query
var query = sqlGenerator.GetSelect(filters);
//Execute the query
return Connection.Query<T>(query, filters).FirstOrDefault();
}
The IRepository Interface has only one method, the GetFirst. A Controller that uses this repository is as follows
public class UsersController : ApiController
{
private IRepository Repository;
public UsersController(IRepository repository)
{
Repository = repository;
}
public User Get(int id)
{
return Repository.GetFirst<User>(new { id });
}
}
I use autofac as DI and in the Application_Start method in Global.asax I use the following code
string connString = ConfigurationManager.ConnectionStrings["DapperDemo"].ConnectionString;
SqlConnection connnection = new SqlConnection(connString);
var builder = new ContainerBuilder();
builder.RegisterType<Repository>().As<IRepository>();
builder.RegisterType<UsersController>().InstancePerRequest();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
But it seems that I am missing something cause I get the following error:
An error occurred when trying to create a controller of type 'UsersController'. Make sure that the controller has a parameterless public constructor.
You need to overwrite default controller activator, because it has no knowledge of your DI container.
Add a service class:
public class ServiceActivator : IHttpControllerActivator
{
public ServiceActivator(HttpConfiguration configuration) { }
public IHttpController Create(HttpRequestMessage request
, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = ObjectFactory.GetInstance(controllerType) as IHttpController;
return controller;
}
}
Then on Application_Start():
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new ServiceActivator(GlobalConfiguration.Configuration));
I'm using structure map in this example, so just replace it with which ever container you are using.

Log method parameters and return type using Enterprise library logging application block

Is there any way to log method parameter name , its value and return type value using Enterprise library logging application block.
I have provided a code sample below. The requirement is to log it's methods input parameters value and its return type value
// Complex Types
public class UserDetails
{
public string UserName { get; set; }
public int UserAge { get; set; }
public string UserAddress { get; set; }
}
public class User
{
public string UserId { get; set; }
public string Pwd { get; set; }
}
//Interface
public interface IService
{
UserDetails GetUserDetails(User ReqUser);
}
//Imp
public class Service : IService
{
[LogCallHandler(Categories = new string[] { "General" }, LogBeforeCall = true, LogAfterCall = true ,
BeforeMessage = "This occurs before the call to the target object",AfterMessage="This occured after method call",IncludeParameters=true)]
public UserDetails GetUserDetails(User ReqUser)
{
UserDetails oUD = new UserDetails();
oUD.UserName = "hhh" + ReqUser.UserId;
oUD.UserAge = 100;
oUD.UserAddress = "HHHHHHHHHHHHHHHHHHHHHHH";
return oUD;
}
#endregion
}
//Usage
private void button2_Click(object sender, EventArgs e)
{
IUnityContainer container = new UnityContainer().LoadConfiguration();
container.AddNewExtension<EnterpriseLibraryCoreExtension>();
IService service = container.Resolve<IService>();
User nUser = new User();
nUser.UserId = "TTTTT";
nUser.Pwd = "XXXXX";
UserDetails mm = service.GetUserDetails(nUser);
}
Could anyone please explain how to implement this using Enterprise library logging application block?
You can write an OnMethodBoundaryAspect to intercept your method calls using PostSharp API.
OnMethodBoundaryAspect.OnEntry method includes MethodExecutionArgs parameter which provides all the information you need about the method and its arguments.
See this post for a sample logging aspect implementation very close to your requirements.
// This method is executed before the execution of target methods of this aspect.
public override void OnEntry( MethodExecutionArgs args )
{
// Build method information to log.
string methodInfo = BuildMethodInformation(args.Arguments);
// continue with your logging...
}
You can get method parameters via Arguments member of MethodExecutionArgs parameter like this:
private string BuildMethodInformation(Arguments arguments)
{
var sb = new StringBuilder();
sb.Append(_methodName);
foreach (var argument in arguments.ToArray())
{
sb.Append(arguments.GetArgument( i ) ?? "null");
}
return sb.ToString();
}
For method parameters, check this or this samples. They are built for caching but BuildCacheKey/GetCacheKey methods include all the information you need to get argument information of a method.
You can use EntLib LogCallHandler by code:
container.AddNewExtension<EnterpriseLibraryCoreExtension>();
container.RegisterType<IService, Service>(
new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<TransparentProxyInterceptor>());
Or by config file:
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
<namespace name="LoggingCallHandler" />
<assembly name="LoggingCallHandler" />
<container>
<extension type="Interception" />
<extension type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity.EnterpriseLibraryCoreExtension, Microsoft.Practices.EnterpriseLibrary.Common" />
<register type="IService" mapTo="Service">
<interceptor type="TransparentProxyInterceptor" />
<policyInjection />
</register>
</container>
</unity>
Here, LoggingCallHandler is namespace/assembly for your service class. Alternatively, you can define your type alias like this:
<alias alias="Service" type="LoggingCallHandler.Service, LoggingCallHandler"/>
<alias alias="IService" type="LoggingCallHandler.IService, LoggingCallHandler"/>
See this or this discussion for full configuration including logging block configuration.

Autofac equivalent of "BuildUp"

Structuremap defines a 'BuildUp' method that takes an already-constructed object and performs setter injection to push in configured dependencies into that object.
Does Autofac have an equivalent method ?
The question was referring to already-constructed objects (ones not registered in the container) so the correct answer is either InjectProperties or InjectUnsetProperties.
The following test demonstrates the behaviour
public class TestPropertyInjection
{
public object ShouldBeInjectedByAutofac { get; set; }
}
[Fact]
public void Autofac_can_inject_properties()
{
var builder = new ContainerBuilder();
builder.RegisterType(typeof(object));
var container = builder.Build();
var existingObjectNotRegisteredInContainer = new TestPropertyInjection();
container.InjectProperties(existingObjectNotRegisteredInContainer);
// can also use InjectUnsetProperties to only set unset properties
//container.InjectUnsetProperties(existingObjectNotRegisteredInContainer);
Assert.NotNull(existingObjectNotRegisteredInContainer.ShouldBeInjectedByAutofac);
}
Try InjectUnsetProperties.
Sample:
public class YourModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<YourClass>().OnActivated(e => e.Context.InjectUnsetProperties(e.Instance));
}
}
In more recent versions of Autofac you can simply use:
builder.RegisterType<YourClass>().PropertiesAutowired();

Autofac WithMetadata not working

This is what I've got:
public interface INamed
{
string Name { get; }
}
public interface IService
{
}
public class Service : IService
{
}
public class ServiceUser
{
public ServiceUser(IEnumerable<Lazy<IService, INamed>> services)
{
var cnt = services.Count(); // Always 0.
}
}
var builder = new ContainerBuilder();
builder.Register(c => new Service())
.As<IService>()
.WithMetadata<INamed>(m => m.For(n => n.Name, "Test"));
builder.RegisterType<ServiceUser>();
var container = builder.Build();
var su = container.Resolve<ServiceUser>();
The collection of Lazy<IService, INamed> services in the ServiceUser ctor is always empty. Can you explain what I'm doing wrong? One thing I immediately don't understand is where the concrete implementation of INamed is coming from. I guess Autofac generates that internally? Please help clear things up for me.
Upgrade to the latest Autofac.