I am trying to convert this code in my DI mapping from Unity to Structuremap but I cannot seem to get it to work. I am using Repository pattern like the one in found in shrinkr by Kazi Manzur Rashid found here http://shrinkr.codeplex.com/ Any help would be appreciated!
Unity Code:
....
private static readonly Func<LifetimeManager> perRequest = () => new PerRequestLifetimeManager();
....
IBuildManager buildManager = container.Resolve<IBuildManager>(); RegisterRepositories(buildManager, container);
....
private static void RegisterRepositories(IBuildManager buildManager, IUnityContainer container)
{
Type genericRepositoryType = typeof(IRepository<>);
IEnumerable<Type> repositoryContractTypes = buildManager.PublicTypes.Where(type => (type != null) && type.IsInterface && type.GetInterfaces().Any(interfaceType => interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition().Equals(genericRepositoryType))).ToList();
foreach (Type repositoryImplementationType in buildManager.ConcreteTypes.Where(implementationType => repositoryContractTypes.Any(contractType => contractType.IsAssignableFrom(implementationType))))
{
foreach (Type repositoryInterfaceType in repositoryImplementationType.GetInterfaces())
{
container.RegisterType(repositoryInterfaceType, repositoryImplementationType, perRequest());
}
}
}
I don't know Unity, but I'm guessing you are trying to make requests for IRepository return a ProductRepository.
In StructureMap, the code is a bit simpler:
var container = new Container(x => {
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.ConnectImplementationsToTypesClosing(typeof(IRepository<>));
});
});
Related
I am working in getting connectionstring with owin startup for tenant .I have MultiTenantOwinMiddleware to process Tenant.I have following code in my Startup class.
I am beginner with Owin.
builder.RegisterType<OwnerDbContext>()
.AsSelf()
.WithParameter(new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof (string) && pi.Name == "ConnectionString",
(pi, ctx) => GetTenantConnectionString(ctx)))
.InstancePerRequest();
private static string GetTenantConnectionString(IComponentContext ctx)
{
var owinContext = ctx.Resolve<IOwinContext>();
var tenant = owinContext.GetCurrentTenant<OwnerTenant>();
return tenant != null ? tenant.ConnectionString : "XYZ";
}
I am getting this error .
The requested service 'Microsoft.Owin.IOwinContext' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Edit
public static void ConfigureIoCContainer(this IAppBuilder app, HttpConfiguration config)
{
var container = RegisterInstances(); // Function for component registration
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.Use(async (ctx, next) =>
{
using (var scope = container.BeginLifetimeScope(b => b.RegisterInstance(ctx).As<IOwinContext>()))
{
ctx.Set<ILifetimeScope>("idsrv:AutofacScope", scope);
await next();
}
});
}
Any any help would be appreciated.
Thank you very much
I am using Sitecore 8.2 Update 4 with Helix framework also using Microsoft Extension Dependency Injection. I have performed few steps for DI:
1. Created DI project in Foundation layer.
2. I have created on pipeline with name Habitat.Foundation.DI.RegisterControllers inside
App_config/Include/zFoundation
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"><sitecore> <services> <configurator type=" Habitat.Foundation.DI.RegisterControllers, Habitat.Foundation.DI" /></services></sitecore></configuration>
namespace Habitat.Foundation.DI{ public class RegisterControllers : IServicesConfigurator
{
public void Configure(IServiceCollection serviceCollection)
{
serviceCollection.AddMvcControllers("*.Feature.*");
}
}}
namespace Habitat.Foundation.DI.Extensions{
public static class ServiceCollectionExtensions
{
public static void AddMvcControllers(this IServiceCollection serviceCollection, params string[] assemblyFilters)
{
var assemblies = GetAssemblies.GetByFilter(assemblyFilters);
AddMvcControllers(serviceCollection, assemblies);
}
public static void AddMvcControllers(this IServiceCollection serviceCollection, params Assembly[] assemblies)
{
var controllers = GetTypes.GetTypesImplementing<IController>(assemblies)
.Where(controller => controller.Name.EndsWith("Controller", StringComparison.Ordinal));
foreach (var controller in controllers)
serviceCollection.AddTransient(controller);
controllers = GetTypes.GetTypesImplementing<ApiController>(assemblies)
.Where(controller => controller.Name.EndsWith("Controller", StringComparison.Ordinal));
foreach (var controller in controllers)
serviceCollection.AddTransient(controller);
}
}}
public static class GetAssemblies
{
public static Assembly[] GetByFilter(params string[] assemblyFilters)
{
var assemblyNames = new HashSet<string>(assemblyFilters.Where(filter => !filter.Contains('*')));
var wildcardNames = assemblyFilters.Where(filter => filter.Contains('*')).ToArray();
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(assembly =>
{
var nameToMatch = assembly.GetName().Name;
if (assemblyNames.Contains(nameToMatch)) return true;
return wildcardNames.Any(wildcard => IsWildcardMatch(nameToMatch, wildcard));
})
.ToArray();
return assemblies;
}
/// <summary>
/// Checks if a string matches a wildcard argument (using regex)
/// </summary>
private static bool IsWildcardMatch(string input, string wildcards)
{
return Regex.IsMatch(input, "^" + Regex.Escape(wildcards).Replace("\\*", ".*").Replace("\\?", ".") + "$",
RegexOptions.IgnoreCase);
}
}public static class GetTypes {
public static Type[] GetTypesImplementing<T>(params Assembly[] assemblies)
{
if (assemblies == null || assemblies.Length == 0)
return new Type[0];
var targetType = typeof(T);
return assemblies
.Where(assembly => !assembly.IsDynamic)
.SelectMany(GetExportedTypes)
.Where(type => !type.IsAbstract && !type.IsGenericTypeDefinition && targetType.IsAssignableFrom(type))
.ToArray();
}
private static IEnumerable<Type> GetExportedTypes(Assembly assembly)
{
try
{
return assembly.GetExportedTypes();
}
catch (NotSupportedException)
{
// A type load exception would typically happen on an Anonymously Hosted DynamicMethods
// Assembly and it would be safe to skip this exception.
return Type.EmptyTypes;
}
catch (ReflectionTypeLoadException ex)
{
// Return the types that could be loaded. Types can contain null values.
return ex.Types.Where(type => type != null);
}
catch (Exception ex)
{
// Throw a more descriptive message containing the name of the assembly.
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
"Unable to load types from assembly {0}. {1}", assembly.FullName, ex.Message), ex);
}
}
}
As I am using Glass Mapper so I want to use ISitecoreContext, for that I have register ISitecoreContext in Foundation/ORM for that I have performed these actions:
1. Created patch file inside Foundation/ORM
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"><sitecore><services>
<configurator type="Habitat.Foundation.ORM.DI.RegisterContainer, Habitat.Foundation.ORM" />
</services> </sitecore>
public class RegisterContainer : IServicesConfigurator
{
public void Configure(IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<ISitecoreContext, SitecoreContext>();
}
}
Accesssing in controller like this
private readonly ISitecoreContext _sitecoreContext;
public TestController(ISitecoreContext sitecoreContext)
{
_sitecoreContext = sitecoreContext;
}
I accessing in two classes one way is _sitecoreContext.GetItem(Context.Site.ContentStartPath) and another way is _sitecoreContext.GetRootItem() then it started throwing error “{"Service has been disposed, cannot create object"}” in _sitecoreContext.GetItem(Context.Site.ContentStartPath) but working for
_sitecoreContext.GetRootItem()
When I update AddTransient to AddSingleton then it works for some time for both but for after some time it started giving me null value of _sitecoreContext.
Please help me.
I have this registration in StructureMap
ObjectFactory.Initialize(x => {
x.For<IPageModel>().UseSpecial(y => y.ConstructedBy( r => ((MvcHandler) HttpContext.Current.Handler).RequestContext.RouteData.GetCurrentModel<IPageModel>()));
});
And then I access this object in my constructor like this
public HomeController(IPageModel model) {}
Now I would like to register all concrete types that implements the interface IPageModel and when asked for I want to use the same For<> statement to get the correct instance.
It seems like i could use Scan together with my own convention to do this but I can't figure out exactly how to do it.
This is some example code
x.Scan(scanner =>
{
scanner.AssembliesFromApplicationBaseDirectory();
scanner.Convention<MySpecialConvetion>();
});
public class MySpecialConvetion : IRegistrationConvention {
public void Process(Type type, Registry registry) {
if(type.IsAssignableFrom(typeof(IPageModel))) {
registry.For<CONCRETE IMPLEMENTATION>().UseSpecial(y => y.ConstructedBy( r => ((MvcHandler) HttpContext.Current.Handler).RequestContext.RouteData.GetCurrentModel<CONCRETE IMPLEMENTATION>()));
}
}
}
Edit: It seems like I need to use the non-generic For, but how can I handle the construction my self using the non-generic For?
I got this working by creating a generic method definition, and used reflection to populate the types. Easier to show than explain:
public class MySpecialConvetion : IRegistrationConvention
{
public static readonly MethodInfo RegisterMethod = typeof (MySpecialConvetion)
.GetMethod("Register", BindingFlags.NonPublic | BindingFlags.Static)
.GetGenericMethodDefinition();
public void Process(Type type, Registry registry)
{
if (type.IsAssignableFrom(typeof (IPageModel)))
{
var specificRegisterMethod = RegisterMethod.MakeGenericMethod(new[] { type });
specificRegisterMethod.Invoke(null, new object[] { registry });
}
}
static private void Register<T>(Registry registry)
where T : IPageModel
{
registry
.For<T>()
.UseSpecial(y => y.ConstructedBy(r => GetCurrentPageModel<T>()));
}
static private T GetCurrentPageModel<T>()
where T : IPageModel
{
var handler = (MvcHandler) HttpContext.Current.Handler;
if (handler == null)
return default(T);
return handler.RequestContext.RouteData.GetCurrentModel<T>();
}
}
I added an intermediate step and checked for a null handler since I didn't have one in my site. But this should get you the missing piece you needed.
I'm trying to write an MSpec test that instantiates one of my controllers with all the correct Ninject bindings. How do I go about doing that? This is what I have so far:
[Subject(Concern.Initialization)]
public class when_permanent_employee_page_is_loaded_for_first_time
{
private static PermanentEmployeeController controller;
Establish context = () =>
{
NinjectControllerFactory controllerFactory = new NinjectControllerFactory();
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
controller = (PermanentEmployeeController)controllerFactory.CreateController(new RequestContext(), "PermanentEmployee");
};
private Because of = () => controller.Index();
private It should_load_all_available_jobs = () =>
{
var blah = controller;
var blah3 = 3;
};
It should_load_all_available_locations;
It should_load_all_available_departments;
}
In the above code I'm simply trying to see if I can instantiate my controller with all the Ninject bindings in tact. The NinjectControllerFactory class looks like this:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new DefaultModule());
public IKernel Kernel
{
get
{
return kernel;
}
set
{
this.kernel = value;
}
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
return (IController)kernel.Get(controllerType);
}
}
And the DefaultModule class like this:
public class DefaultModule : NinjectModule
{
/// <summary>
/// Performs the binding of interfaces to their respective implementations. 'Tis very cool.
/// </summary>
public override void Load()
{
// Data service bindings
Bind<IJobService>().To<JobServiceImpl>().InTransientScope();
Bind<IJobWsWrapper>().To<JobWsWrapperImpl>().InTransientScope();
// View model factory bindings
Bind<IPermanentEmployeeViewModelFactory>().To<PermanentEmployeeViewModelFactoryImpl>().InTransientScope();
}
}
So my question is: is there a way to specify the bindings of my Ninject module in my MSpec test and then have my instantiated controller use those bindings? I want to avoid instantiating my Controller like this: var controller = new Controller() since that doesn't allow me to test the Ninject bindings. I've also looked into the TestControllerBuilder class from the MvcContrib library but I haven't figured out how to instantiate controllers with Ninject bindings with it. Thanks for the help!
Ok I figured out how to initialize my controller along with the Ninject Bindings in my MSpec tests! Well I didn't figure it out. A coworker did but that's irrelevant now. Here is how it's done:
public class when_permanent_employee_page_is_loaded_for_first_time
{
private static Mock<IJobService> jobServiceMock;
private static Mock<IUtilsService> utilsServiceMock;
private static PermanentEmployeeController controller;
private static ContextMocks mocks;
private static IList<Job> jobs = new List<Job>();
private static IList<string> departments = new List<string>();
private static IList<string> locations = new List<string>();
private static PermanentEmployeeJobsViewModel viewModel;
Establish context = () =>
{
jobServiceMock = new Mock<IJobService>();
jobServiceMock.Setup(x => x.GetJobs(1)).Returns(jobs);
jobServiceMock.Setup(x => x.GetDepartmentsFromJobs(jobs)).Returns(departments);
jobServiceMock.Setup(x => x.GetLocationsFromJobs(jobs)).Returns(locations);
utilsServiceMock = new Mock<IUtilsService>();
var kernel = new StandardKernel(new DefaultModule());
kernel.Rebind<IJobService>().ToConstant(jobServiceMock.Object);
kernel.Rebind<IUtilsService>().ToConstant(utilsServiceMock.Object);
controller = kernel.Get<PermanentEmployeeController>();
mocks = new ContextMocks(controller);
};
Because of = () =>
{
PartialViewResult view = (PartialViewResult)controller.Index();
viewModel = (PermanentEmployeeJobsViewModel)view.ViewData.Model;
};
It should_load_all_available_jobs = () =>
{
jobServiceMock.Verify(x => x.GetJobs(1));
jobServiceMock.Verify(x => x.GetDepartmentsFromJobs(jobs));
jobServiceMock.Verify(x => x.GetLocationsFromJobs(jobs));
viewModel.Departments.ShouldEqual(departments);
};
It should_load_all_available_locations;
It should_load_all_available_departments;
}
Ok that's it :). Hopefully someone else can benefit from this answer. Special thanks to my coworker for figuring this out. You know who you are :D
i have a doubt that i am not using the best practice for using Structure-Map.
all working fine but just a confusion in mind.
my code look like this.
global.asax
IContainer container = new Container(
x => {
x.For<IUserRepo>().Use<UserRepo>();
x.For<IPostRepo>().Use<PostRepo>(); // this is the soultion for the error
});
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
PostController
private readonly IPostRepo _postRepo;
public PostController(IPostRepo postRepo)
{
this._postRepo = postRepo;
}
StructureMapDependencyResolver
public class StructureMapDependencyResolver : IDependencyResolver
{
private readonly IContainer _container;
public StructureMapDependencyResolver(IContainer container )
{
this._container = container;
}
public object GetService(Type serviceType)
{
object instance = _container.TryGetInstance(serviceType);
if(instance == null && !serviceType.IsAbstract)
{
_container.Configure(c => c.AddType(serviceType,serviceType));
instance = _container.TryGetInstance(serviceType);
}
return instance;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType).Cast<object>();
}
}
here is the IPostRepo looks like
public interface IPostRepo
{
bool CreatePost(Post newPost);
List<Post> ShowAllPosts();
Post FindPostById(int postId);
Post EditPost(Post editPost);
UserPostCommentViewModel FindAllPostComments(int postId);
int? AddPlusOneToNumberOfViews(int postId);
}
thx martin for your help
No. Like I said in your other question, take out the Controller Activator ... unless you are using it for a purpose (which it doesn't seem like you are).
Also, this line is plain WRONG:
x.ForRequestedType<AccountController>().TheDefault.Is.
ConstructedBy(() => new AccountController(new UserRepo()));
You should not be using new for your UserRepo ... that is what the line above is taking care of:
x.For<IUserRepo>().Use<UserRepo>();
If you take out the ControllerActivator, you should have a nice start to an MVC app.