Ninject Dependency Injection with Asp.Net MVC3 or MVC4 - asp.net-mvc-3

I am using Ninject MVC3(version 3.0.0.0) for my ASP.Net MVC3 application installed using NuGet Package for Dependency Injection.
Here is the Global.asax change:
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("favicon.ico");
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserRepository>().To<UserRepository>();
kernel.Bind<IUserService>().To<UserService>();
kernel.Bind<ICommonRepository>().To<CommonRepository>();
kernel.Bind<ICommonService>().To<CommonService>();
}
}
But it gives the following Error though i have the parameterless Constructor for my HomeController:
System.NullReferenceException: Object reference not set to an instance of an object.
Generated: Wed, 28 Mar 2012 05:49:01 GMT
System.InvalidOperationException: An error occurred when trying to create a controller of type 'MVC3.Web.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at Ninject.Planning.Bindings.BindingConfiguration.GetProvider(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\BindingConfiguration.cs:line 107
at Ninject.Planning.Bindings.Binding.GetProvider(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\Binding.cs:line 212
at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 197
at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 165
at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 114
at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 197
at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 165
at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 114
at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 197
at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 165
at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 114
at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Web.Mvc.NinjectDependencyResolver.GetService(Type serviceType) in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectDependencyResolver.cs:line 56
at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
--- End of inner exception stack trace ---
at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)
at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<BeginProcessRequest>b__2()
at System.Web.Mvc.SecurityUtil.<>c__DisplayClassb`1.<ProcessInApplicationTrust>b__a()
at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust[TResult](Func`1 func)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
UPDATE:
Below is the Code from the HomeController:
public class HomeController : Controller
{
#region Declaration
public ICommonService _commonService { get; set; }
#endregion
#region Constructor
public HomeController()
{
}
public HomeController(ICommonService commonService)
{
this._commonService = commonService;
}
#endregion
public ActionResult Index()
{
return View();
}
Constructor of CommonService and CommonRepository:
public class CommonService : ICommonService
{
#region Declaration
private readonly ICommonRepository _repository;
#endregion
#region Constructor
public CommonService(ICommonRepository repository)
{
this._repository = repository;
}
#endregion
public class CommonRepository : ICommonRepository
{
#region Declaration
private DBContainer _context = new DBContainer();
#endregion
#region Constructor
public CommonRepository()
{
}
#endregion
Am i missing any other Reference here?

This is how constructor selection in Ninject works:
If a constructor has an [Inject] attribute, it is used. If multiple constructors have an [Inject] attribute, Ninject will throw a NotSupportedException.
If no constructors have an [Inject] attribute, Ninject will select the one with the most parameters that Ninject understands how to resolve.
If no constructors are defined, Ninject will select the default
parameterless constructor.
In your case Ninject is most probably not selecting the parameterless constructor because it believes he knows how to resolve ICommonService. Please try to decorate your parameterless constructor with [Inject] attribute if you want Ninject to use it or make further investigation why ICommonService isn't being resolved.

If you recently retargeted the MVC application from .NET 4.0 to 4.5 or the other way around, then you get the exact same symptom. It is fixed by referencing the correct .NET version DLLs for the target.
If you are using the Ninject, Ninject.MVC3 and Ninject.Web.Common nugets then you will find all .NET targets there.

Quote from https://github.com/ninject/ninject/wiki/Injection-Patterns:
The primary DI pattern is Constructor Injection. When activating an instance of a type Ninject will choose one of the type’s constructors to use by applying the following rules in order:-
If a constructor has an [Inject] attribute, it is used (but if you apply the attribute to more than one, Ninject will throw a NotSupportedException at runtime upon detection).
If no constructors have an [Inject] attribute, Ninject will select the one with the most parameters that Ninject understands how to resolve.
If no constructors are defined, Ninject will select the default parameterless constructor (assuming there is one).

Related

The type String cannot be constructed

I'm using Web.api and Unity and I am getting the following error when trying to open the default "help" area:
[InvalidOperationException: The type String cannot be constructed. You must configure the container to supply this value.]
Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.GuardTypeIsNonPrimitive(IBuilderContext context, SelectedConstructor selectedConstructor) +280
Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.PreBuildUp(IBuilderContext context) +356
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlanCreatorPolicy.CreatePlan(IBuilderContext context, NamedTypeBuildKey buildKey) +205
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +231
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +250
Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +101
BuildUp_System.Web.Http.HttpRouteCollection(IBuilderContext ) +202
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +319
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +250
Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +101
BuildUp_System.Web.Http.HttpConfiguration(IBuilderContext ) +202
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +319
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +250
Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +101
BuildUp_API.Areas.HelpPage.Controllers.HelpController(IBuilderContext ) +204
Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +42
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +319
Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +260
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +373
[ResolutionFailedException: Resolution of the dependency failed, type = "API.Areas.HelpPage.Controllers.HelpController", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.
-----------------------------------------------
At the time of the exception, the container was:
Resolving API.Areas.HelpPage.Controllers.HelpController,(none)
Resolving parameter "config" of constructor API.Areas.HelpPage.Controllers.HelpController(System.Web.Http.HttpConfiguration config)
Resolving System.Web.Http.HttpConfiguration,(none)
Resolving parameter "routes" of constructor System.Web.Http.HttpConfiguration(System.Web.Http.HttpRouteCollection routes)
Resolving System.Web.Http.HttpRouteCollection,(none)
Resolving parameter "virtualPathRoot" of constructor System.Web.Http.HttpRouteCollection(System.String virtualPathRoot)
Resolving System.String,(none)
]
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +436
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name, IEnumerable`1 resolverOverrides) +50
Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides) +48
Microsoft.Practices.Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides) +61
Unity.Mvc4.UnityDependencyResolver.GetService(Type serviceType) +140
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +87
[InvalidOperationException: An error occurred when trying to create a controller of type 'API.Areas.HelpPage.Controllers.HelpController'. Make sure that the controller has a parameterless public constructor.]
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +247
System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +438
System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +226
System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +326
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +177
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
I am new to unity and am sure I am missing step(s).
In webapiconfig.cs:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Custom formatter
config.Formatters.Clear();
config.Formatters.Add(new JSONPFormater());
config.EnableSystemDiagnosticsTracing();
//Setup DI
Bootstrapper.Initialise();
}
Bootstraper.cs(default values)
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
}
}
My attempt at a web.config
web.config
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<connectionStrings>
<add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-API-20130708152001;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-API-20130708152001.mdf" />
<add name="<REMOVED>DBEntities" connectionString="metadata=res://*/Models.DAL.<REMOVED>.csdl|res://*/Models.DAL.<REMOVED>.ssdl|res://*/Models.DAL.<REMOVED>.msl;provider=System.Data.SqlClient;provider connection string="data source=<REMOVED>;initial catalog=<REMOVED>;persist security info=True;user id=<REMOVED>;password=<REMOVED>;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
<!--unity setting-->
<unity>
<containers>
<types>
<register type="API.Areas.HelpPage.Controllers.HelpController, API">
<constructor>
<param valu=""></param>
</constructor>
</register>
</types>
</containers>
</unity>
Am I headed in the right direction??
Thanks
Update:
helpcontroller.cs:
public class HelpController : Controller
{
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
public HelpController(HttpConfiguration config)
{
Configuration = config;
}
public HttpConfiguration Configuration { get; private set; }
public ActionResult Index()
{
return View(Configuration.Services.GetApiExplorer().ApiDescriptions);
}
public ActionResult Api(string apiId)
{
if (!String.IsNullOrEmpty(apiId))
{
HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId);
if (apiModel != null)
{
return View(apiModel);
}
}
return View("Error");
}
}
url I am trying to access: http:// hostname:port/Help
I think a better way is to add InjectionConstructor attribute to the default constructor. This attribute forces unity to use the decorated constructor.
Example:
public class HelpController : Controller
{
private const string ErrorViewName = "Error";
[InjectionConstructor]
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
As your code sample, I'm assuming you are on a Controller and not a API Controller (from web api).
Your api controller has a dependency on the constructor from HttpConfiguration. The container problably does not have this definition for this type and consequently does not know how to solve it and the string on the error message should come from this type as a dependency. I recommend you use the GlobalConfiguration static class and access the Configuration property to get a HttpConfiguration instance. You could abstract it in a property, for sample:
// include this namespace
using System.Web.Http;
public class HelpController : Controller
{
// remove the constructors...
// property
protected static HttpConfiguration Configuration
{
get { return GlobalConfiguration.Configuration; }
}
public ActionResult Index()
{
return View(this.Configuration.Services.GetApiExplorer().ApiDescriptions);
}
public ActionResult Api(string apiId)
{
if (!String.IsNullOrEmpty(apiId))
{
HelpPageApiModel apiModel = this.Configuration.GetHelpPageApiModel(apiId);
if (apiModel != null)
{
return View(apiModel);
}
}
return View("Error");
}
}
Now, if you are on a Api Controller, you just can access directly the this.Configuration property that is already on the ApiController (base class for Api controllers) and get a instance of HttpConfiguration.
The reason this happens is because Unity will by default choose to use the constructor with the most parameters thus bypassing the default constructor.
Comment out the two constructors that exist in the HelpController template and add a default one that sets the configuration.
//public HelpController()
// : this(GlobalConfiguration.Configuration)
//{
//}
//public HelpController(HttpConfiguration config)
//{
// Configuration = config;
//}
public HelpController()
{
Configuration = GlobalConfiguration.Configuration;
}
Registering the HttpConfiguration object as an instance in UnityContainer will also help resolve the issue.
Just need to add to add the below line while registering in UnityContainer.
public static void RegisterTypes(IUnityContainer container) {
container.RegisterInstance<HttpConfiguration>(GlobalConfiguration.Configuration);
}
This will help Unity resolve the config parameter, when it invokes the constructor with the parameter.
public HelpController(HttpConfiguration config) {
Configuration = config;
}
I've recently had this error happen on a previously working codebase. The following answer shows what I did to correct it:
Adding Web API and API documentation to an existing MVC project
Basically make the constructor with parameters protected rather than public

MVVM Light IoC not Binding? What am I missing?

I have a windows 7 phone application that I am working on. I made a couple service classes with interfaces but every-time I try to navigate too these views they now crash.
I setup my project to load one of these views as soon as the emulator loads up(through WMAppManifest.xml)
I have something like this
public interface IGpsService
{
void StartGps();
GeoPosition<GeoCoordinate> CurrentPostion();
}
public class GpsService : IGpsService
{
private GeoCoordinateWatcher gpsWatcher;
public GpsService()
{
gpsWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default)
{
MovementThreshold = 20,
};
}
public void StartGps()
{
gpsWatcher.Start();
}
public GeoPosition<GeoCoordinate> CurrentPostion()
{
return gpsWatcher.Position;
}
}
my view model locator
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IGpsService, Design.GpsDataService>();
}
else
{
SimpleIoc.Default.Register<IGpsService, GpsService>();
}
SimpleIoc.Default.Register<AddProductPriceVm>();
}
// AddProductPrice.xaml.cs
public AddProductPrice(IGpsService gpsService)
{
InitializeComponent();
}
Does the Ioc only bind to View Models or something? Is that why it is not working as I have it in my code behind?
I am using a mix of code behind and MVVM as something are just so much easier to do with code behind.
Error Message
MissingMethodException
at System.Activator.InternalCreateInstance(Type type, Boolean nonPublic, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type)
at System.Windows.Navigation.PageResourceContentLoader.BeginLoad_OnUIThread(AsyncCallback userCallback, PageResourceContentLoaderAsyncResult result)
at System.Windows.Navigation.PageResourceContentLoader.<>c__DisplayClass4.<BeginLoad>b__0(Object args)
at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at System.Delegate.DynamicInvokeOne(Object[] args)
at System.MulticastDelegate.DynamicInvokeImpl(Object[] args)
at System.Delegate.DynamicInvoke(Object[] args)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.Dispatch(DispatcherPriority priority)
at System.Windows.Threading.Dispatcher.OnInvoke(Object context)
at System.Windows.Hosting.CallbackCookie.Invoke(Object[] args)
at System.Windows.Hosting.DelegateWrapper.InternalInvoke(Object[] args)
at System.Windows.RuntimeHost.ManagedHost.InvokeDelegate(IntPtr pHandle, Int32 nParamCount, ScriptParam[] pParams, ScriptParam& pResult)
Dies in NavigationFailed
// Code to execute if a navigation fails
private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// A navigation has failed; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
You're injecting the service directly into the View, not the viewmodel. The View is not created using SimpleIoc so has no knowledge of where to resolve your IGpsService reference in the constructor.
Your best bet, if you want to do this, is to inject the IGpsService into your viewmodel and expose it as a property. Add a DataContextChanged event to your view and, when it fires, take the IGpsService from the viewmodel.
Edit:
//AddProductPrice View
<UserControl
DataContext="{StaticResource Locator.AddProductPriceVm}">
/ AddProductPrice.xaml.cs
public AddProductPrice()
{
InitializeComponent();
DataContextChanged+=DataContextChanged
}
void DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var context=sender as AddProductPriceVm;
if(context!=null)
_myGpsService=context.GpsService;
}
//AddProductPriceVm
public class AddProductPriceVm
{
public AddProductPriceVm(IGpsService gpsService)
{
GpsService=gpsService;
}
public IGpsService GpsService{get;set;}
}
The issue isn't really a DI problem, it's just how the MVVM Light works. It expects the view to be there before it permforms and dependency injection. if you wanted to inject things directly into the view then you could look at using Prism (but it's much heavier with lots more scaffolding).

Linq 'Group by' after Migrate from Orchard 1.5.1 to Orchard 1.6

I have a problem with 'group by'.
before Migration to Orchard 1.5.1, I didn't have any problem with this code:
var list = (from r in GetAll()
group new { r.FormulaCatId, r.InputPeriodId, r.CurrencyId } by new { r.FormulaCatId, r.InputPeriodId, r.CurrencyId }
into grp
select (new CatCurPerViewModel
{
FormulaCatId = grp.Key.FormulaCatId,
InputPeriodId = grp.Key.InputPeriodId,
CurrencyId = grp.Key.CurrencyId
}));
but after migration to Orchard 1.6 this problem occurred:
2013-01-10 15:01:25,704 [7] Orchard.Exceptions.DefaultExceptionPolicy - An unexpected exception was caught
System.NotImplementedException: The method or operation is not implemented.
at NHibernate.Linq.CacheableExpressionNode.Resolve(ParameterExpression inputParameter, Expression expressionToBeResolved, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.ExpressionResolver.GetResolvedExpression(Expression unresolvedExpression, ParameterExpression parameterToBeResolved, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByExpressionNode.<>c__DisplayClass1.<GetResolvedKeySelector>b__0(ExpressionResolver r)
at Remotion.Linq.Parsing.Structure.IntermediateModel.ResolvedExpressionCache`1.GetOrCreate(Func`2 generator)
at Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByExpressionNode.CreateResultOperator(ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.ResultOperatorExpressionNodeBase.ApplyNodeSpecificSemantics(QueryModel queryModel, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.IntermediateModel.MethodCallExpressionNodeBase.Apply(QueryModel queryModel, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.QueryParser.ApplyAllNodes(IExpressionNode node, ClauseGenerationContext clauseGenerationContext)
at Remotion.Linq.Parsing.Structure.QueryParser.GetParsedQuery(Expression expressionTreeRoot)
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at SAS.Core.Services.RateService.ListCatCurPer()
at SAS.Core.Controllers.RatesAdminController.Index()
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass13.<InvokeActionMethodWithFilters>b__10()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
the issue happens because in orchard 1.6 the Table property of Orchard.Data.Repository<T> is implemented in the following way:
public virtual IQueryable<T> Table
{
get { return Session.Query<T>().Cacheable(); }
}
and you cant use Group By with Cacheable() - there is an open ticket in HNIbernate Jira
Orchard does that Cacheable() call in order to leverage 2nd level Nhibernate cache.
If you do not use and do not intend to use this 2nd level cache and the corresponding module in Orchard, you can download Orchard source code, and change the implementation of the Table property in Orchard.Data.Repository<T> to
public virtual IQueryable<T> Table
{
get { return Session.Query<T>(); }
}
This will fix your issue.
Or if you do not want to change Orchard sources, you can create your own generic repository class, and wire it up into DependencyContainer (by default Orchard comes with Autofac).
Here is how it can be done with Autofac 2.6.3.862:
public class MyRepository<T> : Orchard.Data.Repository<T> where T:class
{
public MyRepository(ISessionLocator sessionLocator) : base(sessionLocator)
{
}
public override System.Linq.IQueryable<T> Table
{
get { return Session.Query<T>(); }
}
}
public class MyDataModule : Autofac.Module
{
protected override void AttachToComponentRegistration(Autofac.Core.IComponentRegistry componentRegistry, Autofac.Core.IComponentRegistration registration)
{
base.AttachToComponentRegistration(componentRegistry, registration);
Type limitType = registration.Activator.LimitType;
if (!limitType.IsGenericType || limitType.GetGenericTypeDefinition() != typeof (Repository<>)) return;
var epamRepoTye = typeof(MyRepository<>).MakeGenericType(limitType.GetGenericArguments());
registration.Activating += (s, e) =>
{
var locator = e.Context.Resolve<ISessionLocator>();
e.Instance = Activator.CreateInstance(epamRepoTye, new object[] {locator});
};
}
}
Probably (i have not tested this) the MyDataModule class can be simplified if you can guarantee that the assembly containing it will be loaded later than Orchard.Core assembly:
public class MyDataModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(MyRepository<>)).As(typeof(IRepository<>)).InstancePerDependency();
}
}

Mono, ASP.NET MVC 3, Ninject and a default constructor required

I have a working Visual Studio project that I want to run o Mac with Mono and MonoDevelop.
The project is an ASP.NET MVC 3 application with Ninject MVC that basically inject on controller some interface implementations.
After add all ASP.NET MVC dlls and Ninject dependencies to the project, it compiles successfully. But when I go to run it, I have the error:
Default constructor not found for type WebActivatorTest.Controllers.HomeController.
My controller has the following code:
public class HomeController : Controller
{
INotifier _notifier;
public HomeController(INotifier notifier_)
{
_notifier = notifier_;
}
public ActionResult Index()
{
ViewBag.Name = _notifier.Person();
return View();
}
}
I dont wanna have an empty constructor, cause I now have an AppStart code registering my interface:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<WebActivatorTest.Models.INotifier>().To<WebActivatorTest.Models.Notifier>();
}
This code works perfectly on Windows/Visual Studio but does not work on Mono.
Could some one help me?
The full error is:
Server Error in '/' Application
Default constructor not found for type WebActivatorTest.Controllers.HomeController.
Description: HTTP 500. Error processing request.
Stack Trace:
System.MissingMethodException: Default constructor not found for type WebActivatorTest.Controllers.HomeController.
at System.Activator.CreateInstance (System.Type type, Boolean nonPublic) [0x00000] in <filename unknown>:0
at System.Activator.CreateInstance (System.Type type) [0x00000] in <filename unknown>:0
at System.Web.Mvc.DefaultControllerFactory+DefaultControllerActivator.Create (System.Web.Routing.RequestContext requestContext, System.Type controllerType) [0x00000] in <filename unknown>:0
Version information: Mono Runtime Version: 2.10.9 (tarball Tue Mar 20 15:31:37 EDT 2012); ASP.NET Version: 4.0.30319.1
you can add default constructor
public HomeController()
{
}
But i think, you wrong activate Ninject for controllers. You need register ninject factory. Make sure your code in Global.asax like below:
public class MvcApplication : NinjectHttpApplication
{
/// <summary>
/// Registers the global filters.
/// </summary>
/// <param name="filters">The filters.</param>
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
/// <summary>
/// Registers the routes.
/// </summary>
/// <param name="routes">The routes.</param>
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
/// <summary>
/// Called when the application is started.
/// </summary>
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
Also, for examples you can see sample code on MVC3 here
Or you could use the MVC extensions for ninject, as detailed here
I'm assuming this will work with Mono
I'm coming a little late to the party, but this solution helped me.
Override the default constructor:
public HomeController() : this(new Notifier())
{
}
public HomeController(INotifier notifier_)
{
_notifier = notifier_;
}

LinqToHql extension to NHibernate is not registering properly, getting System.NotSupportedException

I'm implementing the "IsLike" extension to LINQ and Nhibernate as outlined in this post by Fabio.
I have the code like so:
public class MyLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqToHqlGeneratorsRegistry()
: base()
{
RegisterGenerator(ReflectionHelper.GetMethodDefinition(() =>
MyLinqExtensions.IsLike(null, null)),
new IsLikeGenerator());
}
}
public class IsLikeGenerator : BaseHqlGeneratorForMethod
{
public IsLikeGenerator()
{
SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() =>
MyLinqExtensions.IsLike(null, null)) };
}
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return treeBuilder.Like(visitor.Visit(arguments[0]).AsExpression(),
visitor.Visit(arguments[1]).AsExpression());
}
}
public static class MyLinqExtensions
{
public static bool IsLike(this string source, string pattern)
{
pattern = Regex.Escape(pattern);
pattern = pattern.Replace("%", ".*?").Replace("_", ".");
pattern = pattern.Replace(#"\[", "[").Replace(#"\]", "]").Replace(#"\^", "^");
return Regex.IsMatch(source, pattern);
}
}
The extension is registered in the configuration (3rd line):
protected void InitializeNHibernateSession()
{
NHibernateConfiguration = NHibernateSession.Init(
new SimpleSessionStorage(),
GetMappingAssemblies(),
GetNHibernateConfig());
NHibernateConfiguration.Properties.Add(
Environment.LinqToHqlGeneratorsRegistry,
typeof(MyLinqToHqlGeneratorsRegistry).AssemblyQualifiedName);
NHibernateSession.RegisterInterceptor(new AuditInterceptor());
}
But when I try running the query I get an exception
System.NotSupportedException was unhandled by user code
Message=Boolean IsLike(System.String, System.String)
Source=NHibernate
StackTrace:
at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression (MethodCallExpression expression)
at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression (Expression expression)
at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.Visit(Expression expression, VisitorParameters parameters)
at NHibernate.Linq.Visitors.QueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
at Remotion.Data.Linq.Clauses.WhereClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
at Remotion.Data.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
at Remotion.Data.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at NHibernate.Linq.Visitors.QueryModelVisitor.Visit()
at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.NhQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression)
at NHibernate.Linq.NhQueryProvider.Execute[TResult](Expression expression)
at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
at MyProject.Data.Specification.LinqSpecRepository`1.FindAllPaged(Specification`1 specification, Int32 currentPage, Int32 noOfItemsPerPage) in c:\source\MyProject\Specification\LinqSpecRepository.cs:line 47
at MyProject.Tests.PersonRepositoryTests_UserSearch.FilteredQuery_CanPerformWildCardAtTheEndSearch() in c:\source\MyProject.Tests\PersonRepositoryTests_UserSearch.cs:line 51
It's like the extensions is not registered or not triggering. The property is is set since I tried adding it to the configuration in the test itself and got an exception that the key already existed.
NHibernate assembly version is 3.0.0.4000
Any suggestions to what I might be doing wrong?
After figuring out what Sharp Architecture does and learning a bit more about the SessionFactory (ie that it cannot be changed) the solution was to add the properties to the NHibernateSession.Init call
var configProperties = new Dictionary<string, string> {{
Environment.LinqToHqlGeneratorsRegistry,
typeof (MyLinqToHqlGeneratorsRegistry).AssemblyQualifiedName
}};
NHibernateConfiguration = NHibernateSession.Init(
new SimpleSessionStorage(),
GetMappingAssemblies(), null,
GetNHibernateConfig(), configProperties, null);
I tried adding the property to the config file but got validation errors on the file. Adding it to the .Init() call worked perfectly though.
Since I know Fabio's example works, it has to be something in your wrapper classes, for which we don't have the source.
What does NHibernateSession.Init do?
When are you building your SessionFactory?

Resources