-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Add a service that allows constructing parts of an ApplicationModel instance #6919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
In MVC, provider types, including I'll work on getting the docs updated, it shouldn't have recommended inheriting from the |
Thank you for quick answer - I really appreciate it. I'll try to explain our use case: We have a in-house developed framework, which generates JavaScript code for available postbacks of the Page. That code does lot of additional stuff (i.e. blocks UI, prevents duplicate postbacks ...). This framework takes all methods of the Page decorated with attribute PostbackHandler, assumes name of the postback to be the name of the method and generates code. It is bit difficult to change this behavior, since it is now used in many projects and would in many cases introduce quite high QA costs. The problem we were facing was, that DefaultPageApplicationModelProvider (which is responsible for extracting page handlers) didn't identify these methods (because their names didn't start with OnPost). That's why we have inherited from DefaultPageApplicationModelProvider. Compressed snippet of our provider (working in 2.1) is following:
As you can see, we were in fact reusing most of the provider functionality and did only small extension on the CreateHandlerModel method. I think this is not possible with adding new IPageApplicationModelProvider - we would have to rewrite complete functionality of the DefaultPageApplicationModelProvider. It seems, that the DefaultPageApplicationModelProvider was nicely prepared for this (documentation + nice virtual CreateHandlerModel method) - is there any other way to do this in 2.2? Thanks a lot for your help. |
A convention like this should work. Could you give it a try? public class PostBackHandlerModelConvention : IPageApplicationModelConvention
{
public void Apply(PageApplicationModel model)
{
var methods = model.HandlerType.GetMethods();
foreach (var method in methods.Where(m => m.IsDefined(typeof(PostbackHandlerAttribute), inherit: true)))
{
var existingPageHandler = model.HandlerMethods.FirstOrDefault(m => m.MethodInfo == method);
if (existingPageHandler != null)
{
// If an existing non-post back handler method exists for the action, remove it since we'll recreate it soon.
model.HandlerMethods.Remove(existingPageHandler);
}
var attribute = method.GetCustomAttribute<PostbackHandlerAttribute>(inherit: true);
model.HandlerMethods.Add(CreatePostbackHandlerMethod(attribute, method));
}
}
private PageHandlerModel CreatePostbackHandlerMethod(PostbackHandlerAttribute attr, MethodInfo method)
{
// create page handler model
...
}
} |
Thanks - I tried it out and it works. I came across two problems, which I had to resolve and it would be great if you could confirm, that it is the only way (no other solution (more elegant) exists):
registering it with:
Is there any other (more proper) way to get around this? Also, during the migration from 2.1 to 2.2 I came across problem with auto-discovery of the controllers (I worked around it by settings assemblies manually using AddApplicationPart - and this solution is fine with me). Should I open the issue for this (so it is documented in case others encounter the same)? Thanks for your help. |
That's true. @rynowak what do you think about having a factory method for application model pieces? e.g.
Your code looks fine. There's some syntactical sugar for Options which might work too: services.AddOptions<RazorPagesOptions>()
.Configure<IModelMetadataProvider>((options, modelMetadataProvider) => { ... }) |
I would generally really prefer to not expose our guts as an API. I need to know more about the scenario. |
@pranavkm - Thanks for the assistance @rynowak - I will try to summarize:
Please let me know if you need any more details. |
OK thanks that makes sense.
From my point of view this is somewhat problematic for us because in means that all of the default implementations are effectively frozen. We have to think about these as official contracts. This is why a lot of these things have gone internal. Rationalizing what kinds of things people are doing is easier when they talk to us about it, so I appreciate your patience.
@pranavkm - What do we need the IMMP for? I think this will be much more resilient to change if we make a service instead.
BTW the compat expectations of an API like this are:
|
We use IMMP to produce the |
Updated the title and description for the issue with the suggested API. @mgubis we'd be happy to accept a PR for this change 👍 |
@pranavkm - I'd be happy to supply a PR for this change. Just as a word of warning - I am not extremely familiar with internals of the .NET Core development (I would even say I am beginner when it comes to .NET Core internals) - so I might need a help here and there. Can I contact you in case of any questions? @rynowak, @pranavkm - Just to refine/summarize the proposed solution (I am not sure whether I've got it right):
Is this solution okay with you? This effectively moves logic away from DefaultPageApplicationModelProvider to DefaultPageApplicationModelPartsProvider - I am not sure whether this is desired. |
1 & 2 look fine. Since Your plan sounds great! |
I have finally managed to implement the changes as agreed (I apologize for the long time it took). Nevertheless, I came across following issue: DefaultPageApplicationModelProvider is currently unit tested. DefaultPageApplicationModelPartsProvider (created by me) is not directly unit tested (I didn't create neither specific tests, nor migrated tests from DefaultPageApplicationModelProvider). Its functionality is indirectly tested via existing unit tests of DefaultPageApplicationModelProvider. Should I also rework related tests or is the indirect testing via DefaultPageApplicationModelProvider sufficient (I am new to the project and would like to have advisement from people working on the project for long time)? Thanks a lot for the patience :). |
Uh oh!
There was an error while loading. Please reload this page.
BTW the compat expectations of an API like this are:
We've been using .NET Core 2.1 for our project so far and tried to upgrade to 2.2. We are using customized IPageApplicationModelProvider. Since we wanted to preserve the functionality of the default razor provider, we are inheriting from DefaultPageApplicationModelProvider (as suggested in official Microsoft paper: https://docs.microsoft.com/en-us/aspnet/core/razor-pages/razor-pages-conventions?view=aspnetcore-2.2 (Replace the default page app model provider). The problem is, that in 2.2, DefaultPageApplicationModelProvider became internal and thus we can't inherit from it.
Is this way of replacing the default page app model provider not supported any more? Is there any other preferred way available?
Thank you.
The text was updated successfully, but these errors were encountered: