How do you instantiate Pages that have constructors in UWP? - dependency-injection

I want to use the Navigation feature in UWP. Unfortunately, the argument to the Navigate method is a type, not an instance of a page. It looks like the activation of this type is done behind the scenes. I question the design decision, but my immediate problem is that all my MVVM forms are instantiated with the view model. Typically I create pages using the Dependency Injection container.
How do you create pages in UWP when they're used with the Navigate method when those pages have DI constructors?

How do you create pages in UWP when they're used with the Navigate method when those pages have DI constructors?
Instead trying to navigate to the page based on its type, you could set the Content of the Frame to an instance that you create yourself:
rootFrame.Content = new YourPage(yourDependency);
The other option is to make sure that all your pages have a default parameterless constructor and inject the dependencies somewhere else, for example in the OnNavigatedTo method as suggested by #Richard Zhang - MSFT.

In UWP, the navigation parameters of Frame.Navigate are Type rather than instances. This is really a design.
In fact, navigating in UWP doesn't require instances, as well as DI, and in general, if you need to combine Page and ViewModel, you can do this:
1. Initialize ViewModel inside the page constructor
Frame
MyFrame.Navigate(typeof(MyPage));
MyPage
private MyViewModel vm;
public MyPage()
{
this.InitializeComponent();
vm = new MyViewModel();
}
2. Initialize ViewModel by passing parameters when navigating
Frame
var vm = new MyViewModel();
MyFrame.Navigate(typeof(MyPage), vm);
MyPage
private MyViewModel vm;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if(e.Parameter!=null && e.Parameter is MyViewModel _vm)
{
vm = _vm;
// do other things
}
}
If you want to reuse pages, you can enable page caching, it will save the current page state (including ViewModel), and use the cache when you next navigate to the page, so you can avoid repeatedly creating ViewModel.
public MyPage()
{
this.InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
}
Best regards.

Related

MVC - How to instantiate, store and make a typed variable available throughout the application, once per page view

I am developing an MVC app to serve multiple domains - each is a branch of a larger company.
A LocalBranch class stores details such as phone, address, email, location coordinates etc.
I want to create a single instance of this class per http request and have it available throughout the application - from within controllers, views, some helper classes and other code.
Is there a recommended way of doing this?
Right now I have it as a property on a BaseController and use ViewBagto pass it to views. But I would prefer it strongly typed in Views if possible.
I don't want to put it in an application variable, because we need to serve different values to different domains.
I would rather avoid a session variable if possible because we might scale up to use multiple servers in the future, and I've heard this doesn't play well with sessions.
Please feel free to update tags / title if you think there is a clearer way of expressing what I'm after. Thank you.
The best way to maintain your state in a web application per request is simply use the HttpContext class.
You need to store your state(LocalBranch) as an Item in the HttpContext:
HttpContext.Current.Items.Add("LocalBranch", GetLocalBranch());
You can fetch the Item all across your application like this:
LocalBranch branch = HttpContext.Current.Items["LocalBranch"] as LocalBranch;
The Items property is simply a key value Dictionary. The value is an object. You will have to check for nulls and this is really similar to the Session object you know. The main difference is the scope. The HttpContext is a dot net object that has a lifetime of an http request.
Now using the HttpContext the way I've shown you is the simplest way to do it.
You can go two steps forward and use a framework called Unity and add a lifetime to your objects.
Unity does much more and the lifetime management is just one gem.
You can create a custom HttpContext lifetime that generates objects per request. Something like this.
And them all you need to do is:
1.Register you LocalBranch class with the HttpContext lifetime.
2.Add a static Current property which will use the Unity container and resolve the correct instance of LocalBranch.
3.Use it something like this: LocalBranch.Current
BTW, you can use Unity's dependency injection for injecting objects into controllers and other modules. That's a better practice then just using the static Current property.
You kind of have two questions here. The first is "How do I create a single instance of this class per HttpRequest?" The second is "How do I make this available to strongly typed views?"
The first has pretty much been answered by #amir-popovich to use dependency injection. However, FWIW I would probably use Ninject instead of Unity (just preference, really) and I would probably implement it differently. I would not use HttpContext, and simply build a service (which is instanciated using Ninject's OnePerHttpRequest Module, passing the domain as an argument to get the proper values).
Then, in order to add these LocalBranch values to your strongly typed View Model, you can first create a base view model which holds this type:
public class BaseViewModel
{
public LocalBranch Branch {get;set;}
}
Then, make all of your current view models inherit this base type
public MyViewModel : BaseViewModel
{
public string SomeValue {get;set;}
}
Then in your controller, it is easy enough to add these values from the service you created from the first step
public ActionResult SomeAction()
{
var vm = new MyViewModel();
vm.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
//do other stuff
return View(vm);
}
However, that gets pretty tedious to add that to each controller action, so you can instead create a Result Filter to add it for you:
public class LocalBranchResultFilter : FilterAttribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
//This method gets invoked before the ActionResult is executed.
filterContext.Controller.ViewData.Model.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
}
}
Now, you can just decorate your Controller and/or Actions with the filter (you could even set it in the Global Filters if you want).
You can embed the child actions into your layout or a view. You can even cache its output so you don't keep re-querying the database.
controller
[ChildActionOnly]
[OutputCache(Duration=500, VaryByParam="*")]
public ActionResult Info()
{
var localBranch = db.GetLocalBranch();
return PartialView("_Info", localBranch);
}
_Info view
This bit will get inserted into your other views
#model LocalBranch
<span>#Model.address</span>
<span>#Model.phone</span>
Use in _Layout or other view
<p>lorem ipsum...</p>
#Html.Action("Info")

unity.mvc4: how to get a reference

I've setup Unity in Bootstrapper.cs of my MVC application, all is working well for constructor injection on my controllers...
My question is when I'm in an ActionResult within a controller I need to get a reference to the container I previously created in Bootstrapper.cs so I can use it to resolve classes for me.
e.g:
public ActionResult Index()
{
//-- container needs a reference to unity container
var testService = container.Resolve<ITestService>();
return View(testService);
}
I need to get a reference to the container
No you don't. You should never need to reference the container (or the DependencyResolver) from within your application.
Use constructor injection instead:
public class HomeController : Controller
{
private readonly ITestService testService;
// constructor
public HomeController(ITestService testService)
{
this.testService = testService;
}
public ActionResult Index()
{
return View(this.testService);
}
}
Since you are using the MVC3 integration package for unity, you probably registered a Unity specific DependencyResolver in the startup path of your application. That looks much like this:
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
When you've done this, your custom DependencyResolver will delegate the creation of controllers to the Unity container and the Unity container is able to inject depdencies of the constructor's of the controllers.
The next thing you should never do is letting views do any work and making them dependent on your services. Views should be dumb and do nothing more than map the data they get from the controller and transform them to HTML (or JSON or whatever).
In other words, do not pass on the testService to the view. Calling the testService from within the view hides that logic, makes the view more complicated, and makes the system hard to test. Since you're using an ITestService abstraction, I assume you want to be able to test your code, but testing the view is not easy (or at least, not as easy as you can test the controller).
What you should do is let the controller call the testService and gather the data that is needed for the view to use. Than pass on that data (perhaps combined in a single class, a view model) to the view.

How can I create a binding in Ninject that changes based on the requested controller?

I have an ASP.NET MVC 3 app, and have run into the following situation. On my page, I have a side bar, which can contain related links specific to that page, i.e., determined by controller type. The links will be determined by the current page's content.
I have followed Phil Haack's blog post on rendering dynamic side bars such as this using Html.Action and a separate controller. I like the separation of concerns this approach gives me: my controllers don't know anything about the side bar at all, which is the way it should be.
I now want to inject an instance of a derived type of SideBar into my SideBarController, an action on which will be called to render the side bar itself. There is one derived type of SideBar per controller, and so I find myself wanting to write code similar to this:
kernel.Bind<SideBar>().ToMethod(_ => controllerName == "foo"
? new FooSideBar(kernel.Get<UrlHelper>())
: new BarSideBar(kernel.Get<UrlHelper>()));
but there's quite a lot that is wrong about that fragment of code, not least the fact that I can't get hold of the controller name in the lambda, and the question of what happens when a third type of controller comes along, and then a fourth, etc.
Note that I can't use WhenInjectedInto<T>(), as the SideBar instance will always be injected into the SideBarController.
For what it's worth, the instances of SideBar are currently being created via the Ninject Factory extension, so the relevant side bar bindings are as follows (I've hard-bound an implementation of SideBar just to prove the approach so far works):
kernel.Bind<ISideBarFactory>().ToFactory().InRequestScope();
kernel.Bind<SideBar>().To<FooSideBar>().InRequestScope();
Finally, I essentially have a one-to-one mapping between the derived types of SideBar and the controller types. It feels a little bit like there might be a bit of duplication here, but also it represents the relationship between the components, so I think I'm ok with it.
This all makes me think that my approach to this part of the problem is wrong, and so I would welcome suggestions on how to achieve a clean solution with Ninject.
I'll have a go at answering, but I'm not near a computer at the moment, and so it'll be a bit vague.
Fundamentally, you can pass another parameter to Html.Action, so if that parameter is either the Request or something gleaned from the Request (such as the controller name or Url parts) then you can use that to determine which sidebar to show. You may need to inject the factory into the sidebar controller, and use it to create the correct controller, or some other fiddling about, but once you know which sidebar is required, it becomes much easier.
I am not sure if this is possible using ninject but it is using ModelBinding like so:
public interface ISidebar
{
}
public class Sidebar1 : ISidebar
{
}
public class Sidebar2 : ISidebar
{
}
public class SidebarModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var controller = controllerContext.RouteData.Values["Controller"];
var action = controllerContext.RouteData.Values["Action"];
switch (controller.ToString())
{
case "Home":
return new Sidebar1();
default:
return new Sidebar2();
}
throw new NotImplementedException();
}
}
public class TestController : Controller
{
public TestController()
{
}
public string Index(ISidebar sidebar)
{
//Do something with it
return "OK";
}
}
//Add to the Application_Start
ModelBinders.Binders.Add(typeof(ISidebar), new SidebarModelBinder());
EDIT: Took me a while, but managed to get it working using Ninject.
Please read it at: http://blog.voltje.be/2012/08/22/creating-a-dynamic-sidebar-with-asp-net-mvc-ninject/
Suggestion:
Don't inject sidebar.
Instead inject [sidebar]ContentProvider.
Bind a default implementation in global asax (per request), then unbind and rebind if needed in the controller.

WP7 and Ninject,how to force the app to get view instances from IoC container

I am using Ninject to inject view model instances into the DataContext property of each view, to avoid using a ServiceLocator, and am using the following syntax inside a NinjectModule as suggested here:
public class TestingModule : NinjectModule
{
public override void Load()
{
Bind<MainPage>().ToMethod(ctx => new MainPage() { DataContext = new MainPageViewModel() }).InSingletonScope();
}
}
If I use:
var x = Kernel.Get<MainPage>();
Then the DataContext property inside x is set to an instance of MainPageViewModel, which is great.
The problem is that the Application does not get the view instances from the DI container when navigating to pages or when starting up, so the DataContext property is never set in any of the views when running the app on a device or inside the emulator.
Does anyone know how I can intercept the creation of views so that I can force the app to retrieve view instances from the DI container?
Have a look at one of the various MVVM frameworks like Caliburn Micro instead of reinventing the wheel. They did a great job making it easy to tie views and view models together while using an IoC container.
Here is a blog post about how to setup Caliburn Micro with Ninject on WP7: http://devlicio.us/blogs/derik_whittaker/archive/2011/07/08/using-ninject-with-commonservicelocator-with-caliburn-micro-on-wp7.aspx
You can add this line into MainPage constructor:
DataContext = Kernel.Get<MainPageViewModel>();

ASP.net MVC -How to use castle windsor's capability to resolve an object inside the view

I have the requirement where I need to make a call to my service from inside of my view. The service I need to call has dependencies to my repositories.
So instead of doing like -
IUserService _userService = new UserService(new UserRepository() );
I would like to obtain the _userService object from Windsor, as it already has all the dependencies resolved.
How can I achieve this ?
The viewwhere I need to call the IUserService is _layout.cshtml inside the Shared Folder. There is no controller specific to this. So where should I be injecting the dependency from?
The functionality I need inside the view is to check for Role based access which I have implemented via UserService. I have 2 choices -
1. Either to use COntext.User.IsInRole inside my view (which is not a testable piece of code)
2. Or call the my UserService from view (which is supported by tests).
I had to choose lesser of two evils so I went with the 2nd choice.
Any inputs will be highly appreciated.
You asked for input. IMO you should not be making calls to a repository from within a view.
I can think of two better options.
Option 1
Put the users roles into a ViewModel which you then pass to the view. Then you query the ViewModel for the roles.
Option 2
Call a ChildAction on your AccountController and return a partial view.
Something like this:
In your View:
Html.Action("GetUserRoles", "Account");
In your Controller:
[ChildActionOnly]
[Transaction]
public PartialViewResult GetUserRoles(string userId)
{
var viewModel = userService.GetRolesForUser(userId);
return PartialView(viewModel);
}
Now you can just inject IUserService via the Controller constructor.
IMO Appart from simple iterations and similar stuff, Views should not contain any code, especially not data access code. That's the whole premise of the MVC pattern.

Resources