MvvmCross cannot find override method for mapping view model to view - view

Has the Setup class methods or hierarchy changed? I cannot seem to find a method called GetViewModelViewLookup to override in the Setup class
I am trying to map a view to a different view model. I am using MvvmCross 3.5.1
I am trying the following
protected override IDictionary<Type, Type> GetViewModelViewLookup()
but it tells me there is not a method named this to override. I am trying to follow the example on the old MvvmCross blog link
Any ideas?
Update * it looks as if the base class used to be MvxBaseSetup which contained GetViewModelToViewLookup, but now it is just MvxSetup which does not contain it.
So how do I override the viewmodel to view mapping now?

If you just want to change the naming scheme, the function to overwrite is CreateViewToViewModelNaming
public class Setup : MvxAndroidSetup
{
public Setup(Context applicationContext) : base(applicationContext)
{
}
protected override IMvxNameMapping CreateViewToViewModelNaming()
{
return new ReverseViewModelNaming();
}
protected override IMvxApplication CreateApp()
{
return new Core.App();
}
protected override IMvxTrace CreateDebugTrace()
{
return new DebugTrace();
}
}
class ReverseViewModelNaming : IMvxNameMapping
{
public string Map(string inputName)
{
// MyView is presented by the view model named weiVyM (how useful :P)
return string.Join("", inputName.Reverse());
}
}
If you want to change the mapping, the function to overwrite is InitializeViewLookup. If you just want to add some extra mappings, call base.InitializeViewLookup().
public class Setup : MvxAndroidSetup
{
public Setup(Context applicationContext) : base(applicationContext)
{
}
protected override void InitializeViewLookup()
{
var registry = new Dictionary<Type, Type>()
{
{ typeof(FirstViewModel), typeof(FirstActivity) },
{ typeof(HomeViewModel), typeof(HomeActivity) } ,
{ typeof(DetailViewModel), typeof(DetailActivity) },
{ typeof(UploadViewModel), typeof(UploadActivity) }
};
var container = Cirrious.CrossCore.Mvx.Resolve<IMvxViewsContainer>();
container.AddAll(registry);
}
protected override IMvxApplication CreateApp()
{
return new Core.App();
}
protected override IMvxTrace CreateDebugTrace()
{
return new DebugTrace();
}
}

Related

Modify ControllerContext in CreateController method of DefaultControllerFactory in asp.net core mvc

I want to override my controllers method. Here i have overriden CreateController method of DefaultControllerFactory to return the CatalogCustomController object if request come for CatalogController.
But the problem is here that i need to pass all the dependency into controller constructor.
public class CustomControllerFactory: DefaultControllerFactory
{
public CustomControllerFactory(ICatalogModelFactory catalogModelFactory,
IProductModelFactory productModelFactory,
IControllerActivator controllerActivator, IEnumerable<IControllerPropertyActivator> propertyActivators)
:base(controllerActivator, propertyActivators)
{
this._catalogModelFactory = catalogModelFactory;
this._productModelFactory = productModelFactory;
}
public override object CreateController(ControllerContext context)
{
if (context.ActionDescriptor.ControllerTypeInfo.AsType() == typeof(CatalogController))
{
return new CatalogCustomController(_catalogModelFactory,
_productModelFactory,
_categoryService,
}
return base.CreateController(context);
}
}
While i want to do it something like this, by modifying
ControllerContext context
public override object CreateController(ControllerContext context)
{
if (context.ActionDescriptor.ControllerTypeInfo.AsType() == typeof(CatalogController))
{
context.ActionDescriptor.ControllerName = "CatalogCustomController";
}
return base.CreateController(context);
}
You could try register Controller into IServiceCollection, and then retrieve Controller from IServiceCollection in CreateController.
Extension method for AddControllersAsServices
public static class Extension
{
public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder)
{
var feature = new ControllerFeature();
builder.PartManager.PopulateFeature(feature);
foreach (var controller in feature.Controllers.Select(c => c.AsType()))
{
builder.Services.TryAddTransient(controller, controller);
}
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
return builder;
}
}
Register Services
services.AddMvc()
.AddControllersAsServices();
CustomControllerFactory
public class CustomControllerFactory : DefaultControllerFactory
{
public CustomControllerFactory(
IControllerActivator controllerActivator, IEnumerable<IControllerPropertyActivator> propertyActivators)
: base(controllerActivator, propertyActivators)
{
}
public override object CreateController(ControllerContext context)
{
if (context.ActionDescriptor.ControllerTypeInfo.AsType() == typeof(CatalogController))
{
return context.HttpContext.RequestServices.GetRequiredService(typeof(CatalogCustomController));
}
return base.CreateController(context);
}
}
I found a solution to do it without registering the controllers as service.
Inherit the custom controller from main one.
In custom controller factory, get the type of requested controller.
Replace the ControllerTypeInfo with the custom one
public override object CreateController(ControllerContext context)
{
Type typeOfController = context.ActionDescriptor.ControllerTypeInfo.UnderlyingSystemType;
if (typeOfController == typeof(Nop.Web.Controllers.CatalogController))
{
context.ActionDescriptor.ControllerTypeInfo = typeof(Controllers.CatalogCustomController).GetTypeInfo();
}
else if (typeOfController == typeof(Nop.Web.Areas.Admin.Controllers.ProductController))
{
context.ActionDescriptor.ControllerTypeInfo = typeof(Areas.Admin.Controllers.ProductCustomController).GetTypeInfo();
}
return base.CreateController(context);
}<pre>

Autofac.Core.DependencyResolutionException ViewModel has not been registered Autofac Xamarin.Forms

Hey everyone I am using Autofac as my DI codebase Im following this solution Using Navigation in MasterDetailPage with Autofac and Xamarin.Forms since my Press button in tabbedPage cannot navigate to next page or link page. using Button={Binding MyNextPage} in xaml.
in that solution I am a little bit confuse about this
builder.RegisterInstance<Func<Page>>(() => ((NavigationPage)Application.Current.MainPage).CurrentPage);
As my Module I register them individually
public class ClientModule : Module
{
//Register Here for Singleton
protected override void Load(ContainerBuilder builder)
{
//RegServ Service
builder.RegisterType<PersonInfoService>().As<IPersonInfoService>().SingleInstance();
builder.RegisterType<PhoneContactService>().As<IPhoneContacts>().SingleInstance();
//RegServ View Model
builder.RegisterType<PersonViewModel>();
builder.RegisterType<PhoneContactViewModelProp>();
builder.RegisterType<LoginViewModel>();
builder.RegisterType<LoginPageViewModel>().SingleInstance();
builder.RegisterType<PersonsViewModel>().SingleInstance();
builder.RegisterType<PersonDetailViewModel>().SingleInstance();
builder.RegisterType<RegistrationViewModel>().SingleInstance();
builder.RegisterType<PhoneContactViewModel>().SingleInstance();
builder.RegisterType<MainPageViewModel>().SingleInstance();
//RegServ Views
builder.RegisterType<MainPage>().SingleInstance();
builder.RegisterType<BarcodePage>().SingleInstance();
builder.RegisterType<CustomScanPageView>().SingleInstance();
builder.RegisterType<CQRCodeOptionPage>().SingleInstance();
builder.RegisterType<PersonPageView>().SingleInstance();
builder.RegisterType<PersonDetailViewPage>().SingleInstance();
builder.RegisterType<RegistrationPage>().SingleInstance();
builder.RegisterType<ClientReadQRPage>().SingleInstance();
builder.RegisterType<LoginPage>().SingleInstance();
builder.RegisterType<PhoneBookPage>().SingleInstance();
}
}
AutofacBootstrapper.cs
namespace FormsSample.Core
{
public abstract class AutofacBootstrapper
{
public void Run()
{
var builder = new ContainerBuilder();
ConfigureContainer(builder);
var container = builder.Build();
var viewFactory = container.Resolve<IViewFactory>();
RegisterViews(viewFactory);
ConfigureApplication(container);
}
protected virtual void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule<AutofacModule>();
}
protected abstract void RegisterViews(IViewFactory viewFactory);
protected abstract void ConfigureApplication(IContainer container);
}
}
AutofacModule.cs
namespace FormsSample.Core
{
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// service registration
builder.RegisterType<ViewFactory>()
.As<IViewFactory>()
.SingleInstance();
builder.RegisterType<Navigator>()
.As<INavigator>()
.SingleInstance();
// navigation registration
builder.Register<INavigation>(context =>
App.Current.MainPage.Navigation
).SingleInstance();
}
}
}
Bootstrapper.cs
namespace FormsSample.Core
{
public class Bootstrapper : AutofacBootstrapper
{
private readonly App _application;
public Bootstrapper(App application)
{
_application = application;
}
protected override void ConfigureContainer(ContainerBuilder builder)
{
base.ConfigureContainer(builder);
builder.RegisterModule<ClientModule>();
// builder.RegisterInstance<Func<Page>>(() => ((NavigationPage)Application.Current.MainPage).CurrentPage);
}
protected override void RegisterViews(IViewFactory viewFactory)
{
// register these with the view factory. ViewModel and View Page
//Autofac <object class, Func<class, >
viewFactory.Register<PersonsViewModel, PersonPageView>();
viewFactory.Register<PersonDetailViewModel, PersonDetailViewPage>();
viewFactory.Register<LoginPageViewModel, LoginPage>();
viewFactory.Register<RegistrationViewModel, RegistrationPage>();
viewFactory.Register<PhoneContactViewModel, PhoneBookPage>();
viewFactory.Register<MainPageViewModel, MainPage>();
}
protected override void ConfigureApplication(IContainer container)
{
// set main page
var viewFactory = container.Resolve<IViewFactory>();
var mainPage = viewFactory.Resolve<MainPageViewModel>();
var navigationPage = new NavigationPage(mainPage);
_application.MainPage = navigationPage;
}
}
}
You are saying
When I replace my entire module using ...
When you actually replace your whole module with the single registration the exception explains itself. Autofac can't resolve the MainPageViewModel since it has not been registered.
You have to register your module and the function that resolves the current page:
builder.RegisterModule<ClientModule>();
builder.RegisterInstance<Func<Page>>(() => ((NavigationPage)Application.Current.MainPage).CurrentPage);
Update 1
Following your last comment, I would expect the Bootstrapper to look like this:
public class Bootstrapper
{
public static void Run()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ClientModule>();
builder.RegisterInstance<Func<Page>>(() => ((NavigationPage)Application.Current.MainPage).CurrentPage);
var container = builder.Build();
var page = container.Resolve<MainPage>();
YourApp.Current.MainPage = new NavigationPage(page);
}
}
Update 2
Given your example I think it should work if you do not comment out the third line in your ConfigureContainer method:
protected override void ConfigureContainer(ContainerBuilder builder)
{
base.ConfigureContainer(builder);
builder.RegisterModule<ClientModule>();
builder.RegisterInstance<Func<Page>>(() => ((NavigationPage)Application.Current.MainPage).CurrentPage);
}

HttpRouteBuilder - Where did it go and Why?

I upgraded my nuget package for the Web API 2 from the RC1 to 5.0.0, and was dumbfounded to find that HttpRouteBuilder, which used to be accessible, was made internal. Along with that, there is no longer an overload for HttpConfiguration.MapHttpAttributeRoutes that takes HttpRouteBuilder as an argument. Why?
I was using that, and it solves a major problem in my project. What do I use instead?
Background:
I am writing a server that uses Attribute Routing for Web API 2. I implemented a class that inherited from HttpRouteBuilder so that I could inject a couple extra path segments to every URI. For example, if the default route builder ended up creating a route for //myserver/user/update, my route builder would modify that route to //myserver/{instance}/user/update. I wanted this done automatically so that I didn't have to stick that in every single of my hundreds of HttpGet, HttpPost, etc. attributes. So now how do I handle that with this major change?
That internalling broke something I was working on as well.
A change set made on August 21st 2013 made this api alteration to fix this issue. According to that issue the only reason functionality was removed was to make Web Api closer to MVC's api. Not a particularly good justification in my opinion.
To resolve my issues I implemented a custom IHttpActionSelector derived from ApiControllerActionSelector. I hope it is not going to be my final solution since it really is far too much code for a simple thing. This approach should work for your problem too.
In my project each route needs to be modified according to which assembly it was found in. In following simplified code every route is prefixed with /Api (before a controller's RoutePrefixAttribute if present).
The actual IHttpActionSelector:
public class PrefixWithApiControllerActionSelector : WrappingApiControllerActionSelector {
protected override HttpActionDescriptor WrapHttpActionDescriptor(HttpActionDescriptor actionDescriptor) {
if (actionDescriptor is ReflectedHttpActionDescriptor)
return new PrefixWithApiReflectedHttpActionDescriptor((ReflectedHttpActionDescriptor)actionDescriptor);
return actionDescriptor;
}
}
public abstract class WrappingApiControllerActionSelector : ApiControllerActionSelector {
protected abstract HttpActionDescriptor WrapHttpActionDescriptor(HttpActionDescriptor actionDescriptor);
public override ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor) {
return base.GetActionMapping(controllerDescriptor).SelectMany(grouping => {
return grouping.Select(actionDescriptor => new KeyValuePair<string, HttpActionDescriptor>(grouping.Key, WrapHttpActionDescriptor(actionDescriptor)));
}).ToLookup(_ => _.Key, _ => _.Value);
}
}
The part that changes the route:
public class PrefixWithApiHttpRouteInfoProvider : WrappedHttpRouteInfoProvider {
public PrefixWithApiHttpRouteInfoProvider(IHttpRouteInfoProvider infoProvider, HttpControllerDescriptor controllerDescriptor) : base(infoProvider, controllerDescriptor) { }
public override string Template {
get {
var parts = new List<string>();
parts.Add("Api");
var prefix = ControllerDescriptor.GetCustomAttributes<RoutePrefixAttribute>().FirstOrDefault();
if (prefix != null && !string.IsNullOrEmpty(prefix.Prefix)) {
parts.Add(prefix.Prefix);
}
if (!string.IsNullOrEmpty(InfoProvider.Template)) {
parts.Add(InfoProvider.Template);
}
var route = "~/" + string.Join("/", parts);
if (route.Length > 2 && route.EndsWith("/", StringComparison.Ordinal)) {
route = route.Substring(0, route.Length - 1);
}
return route;
}
}
}
public abstract class WrappedHttpRouteInfoProvider : IHttpRouteInfoProvider {
private readonly IHttpRouteInfoProvider _infoProvider;
private readonly HttpControllerDescriptor _controllerDescriptor;
protected WrappedHttpRouteInfoProvider(IHttpRouteInfoProvider infoProvider, HttpControllerDescriptor controllerDescriptor) {
_infoProvider = infoProvider;
_controllerDescriptor = controllerDescriptor;
}
public virtual string Name {
get { return InfoProvider.Name; }
}
public virtual string Template {
get { return _infoProvider.Template; }
}
public virtual int Order {
get { return InfoProvider.Order; }
}
protected HttpControllerDescriptor ControllerDescriptor {
get { return _controllerDescriptor; }
}
protected IHttpRouteInfoProvider InfoProvider {
get { return _infoProvider; }
}
}
The glue:
public class PrefixWithApiReflectedHttpActionDescriptor : WrappedReflectedHttpActionDescriptor {
public PrefixWithApiReflectedHttpActionDescriptor(ReflectedHttpActionDescriptor descriptor) : base(descriptor) {}
public override Collection<T> GetCustomAttributes<T>(bool inherit) {
if (typeof(T) == typeof(IHttpRouteInfoProvider)) {
var attributes = Descriptor.GetCustomAttributes<T>(inherit).Cast<IHttpRouteInfoProvider>().Select(_ => new PrefixWithApiHttpRouteInfoProvider(_, Descriptor.ControllerDescriptor));
return new Collection<T>(attributes.Cast<T>().ToList());
}
return Descriptor.GetCustomAttributes<T>(inherit);
}
public override Collection<T> GetCustomAttributes<T>() {
if (typeof(T) == typeof(IHttpRouteInfoProvider)) {
var attributes = Descriptor.GetCustomAttributes<T>().Cast<IHttpRouteInfoProvider>().Select(_ => new PrefixWithApiHttpRouteInfoProvider(_, Descriptor.ControllerDescriptor));
return new Collection<T>(attributes.Cast<T>().ToList());
}
return Descriptor.GetCustomAttributes<T>();
}
}
public abstract class WrappedReflectedHttpActionDescriptor : ReflectedHttpActionDescriptor {
private readonly ReflectedHttpActionDescriptor _descriptor;
protected WrappedReflectedHttpActionDescriptor(ReflectedHttpActionDescriptor descriptor) : base(descriptor.ControllerDescriptor, descriptor.MethodInfo) {
_descriptor = descriptor;
}
public override HttpActionBinding ActionBinding {
get { return Descriptor.ActionBinding; }
set { Descriptor.ActionBinding = value; }
}
public override Collection<T> GetCustomAttributes<T>(bool inherit) {
return Descriptor.GetCustomAttributes<T>(inherit);
}
public override Collection<T> GetCustomAttributes<T>() {
return Descriptor.GetCustomAttributes<T>();
}
public override Collection<System.Web.Http.Filters.FilterInfo> GetFilterPipeline() {
return Descriptor.GetFilterPipeline();
}
public override Collection<System.Web.Http.Filters.IFilter> GetFilters() {
return Descriptor.GetFilters();
}
public override System.Collections.Concurrent.ConcurrentDictionary<object, object> Properties {
get { return Descriptor.Properties; }
}
public override IActionResultConverter ResultConverter {
get { return Descriptor.ResultConverter; }
}
public override Collection<HttpMethod> SupportedHttpMethods {
get { return Descriptor.SupportedHttpMethods; }
}
public override Collection<HttpParameterDescriptor> GetParameters() {
return Descriptor.GetParameters();
}
public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken) {
return Descriptor.ExecuteAsync(controllerContext, arguments, cancellationToken);
}
public override string ActionName {
get { return Descriptor.ActionName; }
}
public override Type ReturnType {
get { return Descriptor.ReturnType; }
}
protected ReflectedHttpActionDescriptor Descriptor {
get { return _descriptor; }
}
}
To use this functionality just substitute the IHttpActionSelector service with PrefixWithApiControllerActionSelector in the config.
If you find a cleaner way of doing things please post your solution!

ASP.NET MVC 3 custom attribute with Ninject not executing

I must be doing something wrong because I have replicated many answers on this subject. My attribute binding is not being hit and I'm not sure why.
Controller.cs
[NatGeoUserAccessAuthorization]
[HttpGet]
public virtual ActionResult Teacher(string id)
{
Attribute/Fitler
public class NatGeoUserAccessAuthorizationAttribute : FilterAttribute{}
public class NatGeoUserAccessAuthorizationFilter : IAuthorizationFilter
{
private readonly IUsersService _usersService;
public NatGeoUserAccessAuthorizationFilter(IUsersService usersService)
{
_usersService = usersService;
}
public string QueryStringName { get; set; }
#region Implementation of IAuthorizationFilter
public void OnAuthorization(AuthorizationContext filterContext)
{
if (!_usersService.HasUserAccess(filterContext.HttpContext.User.Identity.Name, filterContext.HttpContext.Request.QueryString[QueryStringName ?? "id"]))
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "action", "AccessDenied" }, { "controller", "Error" } });
}
}
#endregion
}
Global.asax
protected void Application_Start()
{
// NLog Custom Layouts
ConfigurationItemFactory.Default.LayoutRenderers.RegisterDefinition("utc_date", typeof(UtcDateRenderer));
ConfigurationItemFactory.Default.LayoutRenderers.RegisterDefinition("web_variables", typeof(WebVariablesRenderer));
// Setup IoC Container
DependencyResolver.SetResolver(Bootstrap.Configure((kernel) =>
{
kernel.Bind<IDatabaseFactory>().To<DatabaseFactory<MySqlConnection>>().InRequestScope().WithConstructorArgument("connectionString", Config.Data.MySQLConnection);
ManagerBindings.Register(kernel);
ProviderBindings.Register(kernel);
RepositoryBindings.Register(kernel);
ServiceBindings.Register(kernel);
ValidationBindings.Register(kernel);
kernel.BindFilter<NatGeoUserAccessAuthorizationFilter>(FilterScope.Action, 0).WhenActionMethodHas<NatGeoUserAccessAuthorizationAttribute>();
kernel.Bind<IUserProfile>().To<UserProfile>();
kernel.Inject(Roles.Provider);
}));
// Custom Default Model Binder
ModelBinders.Binders.DefaultBinder = new ValidationModelBinder();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
Bootstrap.cs
public class Bootstrap
{
public delegate void IocRegistrationDelegate(IKernel kernel);
public static IDependencyResolver Configure(IocRegistrationDelegate serviceBindings)
{
var kernel = new StandardKernel();
serviceBindings.Invoke(kernel);
return new NinjectDependencyResolver(kernel);
}
}
You are using an own bootstrapping mechanism that doesn't support filter bindings. Read the docu how to use the one that comes with Ninject.Mvc3 on http://github.com/ninject/ninject.web.mvc/wiki

Ninject multiple modules

I didnt think this would be a problem originally, but as I keep getting exceptions thought I would post here incase im being an idiot...
I have 2 module classes, one sets up NHibernate and one sets up MVC Controllers, now the problem I have is that I have something like below:
public class NHibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionManager>().To<SessionManager>();
}
}
public class ControllerModule : NinjectModule
{
public override void Load()
{
Bind<SomeController>().ToSelf()
.WithConstructorArgument("sessionManager", Kernel.Get<ISessionManager>());
}
}
Whenever I try to use the controller, it just bombs out telling me that its having problems binding the sessionManager argument. I make sure the list has the Nhibernate module in before the Controller module when I create the kernel.
Is there anything immediately stupid in what im doing above?
Assuming:
public class SomeController : Controller
{
private readonly ISessionManager _sessionManager;
public HomeController(ISessionManager sessionManager)
{
_sessionManager = sessionManager;
}
public ActionResult Index()
{
return View();
}
}
The following should be sufficient:
public class NHibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionManager>().To<SessionManager>();
}
}
public class ControllerModule : NinjectModule
{
public override void Load()
{
Bind<SomeController>().ToSelf();
}
}
and in Global.asax:
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.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new NHibernateModule(),
new ControllerModule()
};
return new StandardKernel(modules);
}
}

Resources