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

MVC Assets from DI + Multiproject MVC Design Notes #4089

Closed
danroth27 opened this issue Feb 12, 2016 · 6 comments
Closed

MVC Assets from DI + Multiproject MVC Design Notes #4089

danroth27 opened this issue Feb 12, 2016 · 6 comments
Assignees
Milestone

Comments

@danroth27
Copy link
Member

Some design notes on this topic and a few related bugs.
#4087
#4014

Summary

We want to separate the configuration setting to use DI for creating controllers et al from specifying what assemblies and types to include as controllers. We're looking to support the scenarios users have been asking for with using MVC assets and views from multiple projects/assemblies.

DI

We're going to start by decoupling AddControllersAsServices() from specifying which assemblies should be considered "MVC" assemblies. There are lots of requests for more flexibility to register an "MVC" assembly at startup time, and that shouldn't be tied to the decision to use DI.

Additionally, we want to add support for AddViewComponentsAsServices() and AddTagHelpersAsServices().

All three of these methods (or something with better names) will just be extensions on the MVC builder. That replace their respective IFooActivator with an implementation using DI.

Using Multiple Projects/Assemblies

We want to make it easier to compose MVC's default behavior with the kinds of startup-configured apps that developers have been asking for. We also want to simplify some scenarios around creating redistributable components that provide content/views/controllers.

To accomplish this, we're going to provide a new configurable item on MvcOptions - ApplicationParts. There is basically a 1-1 mapping between an Application Part and and an assembly. Startup code that modifies MvcOptions will see MvcOptions.ApplicationParts pre-populated with an entry for each assembly we'd consider as an "MVC" assembly by default.

You'll also be able to modify an individual Part to do things like include/exclude controllers and view components. We also want to add more goodies here, like the ability to auto-detect that an assembly contains embedded Razor sources or precompiled views.

The Complication

The complication is that Application Parts need to expose and interact with arbitrary features, including types we don't reference from Mvc.Core.

We'll want Application Parts to support a feature-collection-like pattern

Examples

AddMvc(options =>
{
    // Load and use all assemblies in the Plugins directory
    options.ApplicationParts.AddRange(Directory.EnumerateFiles(".../Plugins/*.dll").Select(f => Assembly.Load(f));
})
.AddControllersAsServices(); // Use DI for activation
// Example 3rd party component
public static IMvcBuilder AddBlog(this IMvcBuilder builder)
{
    builder.AddMvcOptions(options =>
    {
        options.ApplicationParts.Add("Blog", typeof(Blog).Assembly);
    });
}

AddMvc().AddBlog().AddMvcOptions(options =>
{
    // Don't use embedded views from this assembly
    options.ApplicationParts["Blog"].SetEmbeddedRazorFileProvider(null); 
})

API Skeleton

public class MvcOptions
{
    public ApplicationPartsCollection ApplicationParts { get; }

    ...
}
public class ApplicationPartsCollection : Collection<ApplicationPart>
{
    public void Add(Assembly assembly)
    public void Add(ApplicationPart part)

    public void AddFeature(IApplicationPartFeatureProvider feature);
}
public class ApplicationPart
{
    public ApplicationPart(Assembly assembly);

    public void SetFeature(IApplicationPartFeature feature);
    public void GetFeature<TFeature>();
}
public interface IControllerFeature
{
    IList<TypeInfo> ControllerTypes { get; }
}
public static class ControllerFeatureApplicationPartExtensions
{
    public static IList<TypeInfo> GetControllerTypes(this ApplicationPart part);
}
@pranavkm
Copy link
Contributor

Should we also consider registering an EmbeddedFileProvider for views from these assemblies?

@rynowak
Copy link
Member

rynowak commented Feb 29, 2016

Ignore what I wrote earlier - we came up with something simpler.

@rynowak rynowak changed the title Add a way to inject MVC constructs (view components, controllers, etc) from an assembly MVC Assets from DI + Multiproject MVC Design Notes Mar 2, 2016
@rynowak rynowak assigned javiercn and unassigned rynowak Mar 4, 2016
@dazinator
Copy link

This looks like a great new helpful API for component / assembly registration!

I love the idea of being able to register a part with a friendly name - like "Blog".

Would that name act as a dictionary key for the part? My concern would be that if it was a unique key, you might get key collisions between multiple components that aren't aware of each others name (Think of developers creating third party modules for the system, not knowing what modules a particular application may already have installed). I guess though this could be overcome by allowing the name to be passed as an argument in the third party extension method, and then letting the application decide of a suitable name to use that was somehow guaranteed to be unique (i.e prefixing the assembly name etc) - but then the name looses it's "friendliness" so not ideal.

I'd love the ability to also get at the list of this parts so i could render them in a view within my application. If you can make some simple service to expose them than that would be great, as I could inject this into a controller and render a view listing the installed parts. That would be fantastic. I wouldn't wish to modify the parts at that point, just list the parts that are currently registered.

@Eilon
Copy link
Member

Eilon commented Mar 17, 2016

I don't think this particular feature is intending to solve the "3rd party component registration" problem - that's a much bigger problem, and naming is just one tiny part of that problem. This is more about a single large app that is split into multiple projects, but are all "owned / developed / controlled" by one organization.

@pekkah
Copy link

pekkah commented Mar 24, 2016

Why add another composition feature when you could extend the Areas feature to cover also this?

@Eilon
Copy link
Member

Eilon commented Mar 24, 2016

@pekkah I would actually say that this simply works very well with areas. This assets thing is about deciding which content to "load" for an MVC app. And "areas" decides the grouping of controllers/routes/views.

javiercn added a commit that referenced this issue Mar 26, 2016
This commit introduces application parts as a concept on MVC.

An application part is an abstraction that allows you to expose some
feature or corncern in a way that is decoupled from their underlying source.
Examples of this include types in an assembly, emdeded resources, files on
disk etc.

Application parts are configured during startup by adding or removing them from
the application part manager available as part of IMvcBuilder and IMvcCoreBuilder.

The application part manager provides the ability to populate features from the
list of available application parts by using a list of application feature providers.
Application feature providers are responsible for populating a given feature given a
list of application parts.

Examples of application providers can be a ControllerFeatureProvider
that goes through the list of application parts, sees which one of those parts exposes types,
determines which of those types are controller types, and adds them to a ControllerFeature
that holds a list of all the types that will be considered controllers in the application.
javiercn added a commit that referenced this issue Mar 30, 2016
This commit introduces application parts as a concept on MVC.

An application part is an abstraction that allows you to expose some
feature or corncern in a way that is decoupled from their underlying source.
Examples of this include types in an assembly, emdeded resources, files on
disk etc.

Application parts are configured during startup by adding or removing them from
the application part manager available as part of IMvcBuilder and IMvcCoreBuilder.

The application part manager provides the ability to populate features from the
list of available application parts by using a list of application feature providers.
Application feature providers are responsible for populating a given feature given a
list of application parts.

Examples of application providers can be a ControllerFeatureProvider
that goes through the list of application parts, sees which one of those parts exposes types,
determines which of those types are controller types, and adds them to a ControllerFeature
that holds a list of all the types that will be considered controllers in the application.
javiercn added a commit that referenced this issue Mar 30, 2016
This commit introduces application parts as a concept on MVC.

An application part is an abstraction that allows you to expose some
feature or corncern in a way that is decoupled from their underlying source.
Examples of this include types in an assembly, emdeded resources, files on
disk etc.

Application parts are configured during startup by adding or removing them from
the application part manager available as part of IMvcBuilder and IMvcCoreBuilder.

The application part manager provides the ability to populate features from the
list of available application parts by using a list of application feature providers.
Application feature providers are responsible for populating a given feature given a
list of application parts.

Examples of application providers can be a ControllerFeatureProvider
that goes through the list of application parts, sees which one of those parts exposes types,
determines which of those types are controller types, and adds them to a ControllerFeature
that holds a list of all the types that will be considered controllers in the application.
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

7 participants