Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Strongly-typed view component. #3900

Closed
mpawelski opened this issue Jan 11, 2016 · 1 comment
Closed

Strongly-typed view component. #3900

mpawelski opened this issue Jan 11, 2016 · 1 comment

Comments

@mpawelski
Copy link

I read about View Components and wonder if there are any plans to make them more compile safe.

Right now I'm working on providing something similar to View Components in current ASP.NET MVC 5 stack and it doesn't seems that hard to implement it in strongly-typed fashion.

The basic idea is that you have "invoke component" helper function where you provide the component type as type parameter (which makes it strongly typed), and a lambda function that get component instance as argument and returns components result. Everything is strongly typed, no magic strings and Invoke methods with params object[] args).

Inside our "invoke component" function we create instance of our component class (using IOC container) and invoke our passed delegate with this component instance, and basing on a model and view name returned by this delegate we render the HTMLs.

This is simile proof of concept:

The invocation of component in view looks like this:

@(Html.Component<FooBarController>(c => c.Invoke(foo: "foo", bar: true))

And this is the FooBarController (just a normal controller that returns partial view, it can be also used with Html.Action call):

public class FooBarController : Controller
{
    public PartialViewResult Invoke(string foo, bool bar)
    {
        var viewName = ... //get view name
        var model = ... //get model
        return PartialView(viewName, model);
    }
}

And this is the code for Html.Component method (alternative to current IViewComponentHelper.Invoke method):

public static MvcHtmlString Component<TComponent>(
   this HtmlHelper htmlHelper,
   Func<TComponent, PartialViewResult> invokeComponent) where TComponent : class
{
    var instance = IocContainer.Get<TComponent>();

    var result = invokeComponent(instance);

    var viewName = ((PartialViewResult)result).ViewName;

    var viewPath = ... // resolve path to view file basing on you View location convention and viewName                        

    var component = htmlHelper.Partial(viewPath, new ViewDataDictionary(((PartialViewResult)result).Model));            

    return component;    
}

The code is simplified to just show the idea but I tested it and it's working.

Can we have something similar in ASP.NET MVC 6?

Maybe we could even have razor support like for TagHelpers. For example we could write such directive:

@addViewCompoenent "*, MyApp.ViewComponents"

and then this code ("Controller" or "Component" suffix could be omitted, like in C# for attributes):

@Component.FooBar("foo", bar: true)

would be translated under the hood to something like this:

@(Html.Component<MyApp.ViewComponents.FooBarController>(c => c.Invoke("foo", bar: true))

we would still get IntelliSense when calling @Component.FooBar("foo", bar: true) just like for TagHelpers in asp-for arguments. Notice that I can even use named arguments, it's just normal method call.

@danroth27
Copy link
Member

We plan to address view component invocation by supporting invoking view components as tag helpers #1051.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants