Skip to content

Lightweight and fast alternative to Partial View #38551

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

Closed
sergei66666 opened this issue Nov 21, 2021 · 4 comments
Closed

Lightweight and fast alternative to Partial View #38551

sergei66666 opened this issue Nov 21, 2021 · 4 comments
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-mvc-razor-views Features related to the Razor view engine for Razor pages and MVC views ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Status: Resolved

Comments

@sergei66666
Copy link

Is your feature request related to a problem? Please describe.

Hello dear developers.

Recently I had a need to remake the html emails so that RazorViewToStringRenderer is used to create them. The specificity of html emails is such that there is one general layout and many repeating pieces (for example, buttons, tables, links with the same style, etc.).

At first I decided to use PartialView. However, there can easily be 10-20 PartialViews inside the letter.
And the performance of such solution turned out to be only two to three times faster than the previous implementation (ashamed to say, but used StringBuilder and Replace).

I thought that I should abandon the Partial View and came to the conclusion that it would be ideal to use the block
@functions inside * .cshtml and put content from Partial Views there.
And this, as expected, turned out to be two to three times faster compared to the implementation based on PartialViews.

But there is a problem. The content from the @functions block cannot be inherited (please correct me if I'm wrong).
Therefore, now I need to either copy the @functions block in each letter (duplication is not good) or use PartialViews (but this is much slower).

Describe the solution you'd like

Can we make it possible to have access to the @functions block declared in a different layout?

I see two possible options

Option 1

We create a special attribute (for example, ShareFunctionsBlockAttribute). It has two parameters: the name of the output class and the namespace. If this attribute is specified in * .cshtml, then when compiling * .cshtml:

  1. a class with the name specified in the attribute is generated and placed in the specified namespace
  2. the modifier partial and abstract is put on the generated class
  3. the generated class is made generic
  4. the ExecuteAsync function is removed.

This will allow:

  1. Manually Create a generic abstract partial class with the same name specified in the attribute, declare the necessary partial functions, but implement them inside the generated class (which based on * .cshtml)
  2. Inherit all the necessary View from the class from the previous paragraph.
  3. Inside these Views, we can use the functions from the @functions block

Option 2

Give View access to the @functions block declared in the file referenced by the Layout property (for example, in _Layout.cshtml).
But it is difficult for me to think over the implementation details. Could be by automatically inheriting from _Layout .cshtml (or some other file specified by the Layout property).

Conclusion

As a result, we will get a faster alternative to Partial Views. I'm not specifically talking about replacement, because there are certainly cases where Partial Views will come in handy.

Dear developers, what do you think about this proposal?

ps Everything described was tested on .net 6
pss At the moment I am using Source Generator which does it for me. It does not use a partial class, but makes an implementation of the interface that I created by hand. But there is a drawback - it only supports simple cases.

@javiercn javiercn added area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-mvc-razor-views Features related to the Razor view engine for Razor pages and MVC views labels Nov 22, 2021
@javiercn
Copy link
Member

@sergei66666 thanks for contacting us.

We think that using components is a better option than partial views for these scenarios and we have a workitem tracking enabling this.

I'm going to close this issue and suggest you upvote the other issue instead for us to keep track of it. #38114

@javiercn javiercn added the ✔️ Resolution: Duplicate Resolved as a duplicate of another issue label Nov 22, 2021
@ghost ghost added the Status: Resolved label Nov 22, 2021
@sergei66666
Copy link
Author

sergei66666 commented Nov 23, 2021

@javiercn Sorry to disturb you. I examined the link you attached. And I don't fully understand how this can help.

I will give a more detailed example to describe the situation. We have a console application (web job) that sends html letters.
Usually there are several different html emails in a project. For example, registration confirmation, password change, password recovery and hundreds of other emails, depending on the project.
All of these letters have:

  1. a single structure like a simple web page: html, head, body.
  2. uniform style of all letters. This is achieved by using building blocks with the same style. Usually everything is built on tables. Links, buttons, text, pictures are already placed inside these tables. As a result, you get 5, 10 or 20 blocks, from which letters will be built.

Therefore, it seems to me that it is very convenient to use the MVC approach here.
Create the _Layout.cshtml file and put the general structure in it.
For each block, we create our own implementation, which will display it. Currently, only partial view and view component can be used as an implementation.

Then, for example, we create ConfirmEmail.cshtml, specify to use _Layout.cshtml and form the structure of the letter from the blocks created earlier.

The problem is that using a partial view and a view component for such purposes is slow and I would say overengineering.
My suggestion is to declare blocks inside @functions and allow to use those blocks in all emails.
This will work much faster, and it seems much more convenient to use.

A short example

@functions
{
	public void GenerateTableWithText(string text)
	{
		<table border="0" cellpadding="0" cellspacing="0" width="" class="" style="">
            <tbody>
                <tr>
                    <td align="center" valign="top" class="description">
                        <p class="text descriptionText" style="">
                            @text
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>
	}
}

I would appreciate if you could show how your suggestion for using components would help simplify this situation.
I really can't figure it out.

@javiercn
Copy link
Member

@sergei66666 what I'm pointing out is that we don't plan to make investments in this area, and that to achieve your goal you'll be better served with using Razor components, which are the lightweight alternative we recommend for "lightweight" partial views.

@sergei66666
Copy link
Author

sergei66666 commented Nov 23, 2021

Thanks. I decided to try Razor Components. I suffered a little to run it in a console application.

The results are not encouraging. If we compare different implementations in terms of speed and memory, then:

  1. The option I offered is the fastest
  2. Partial Views and View Components are two to three times slower than option 1. In memory, it is approximately the same as option 1.
  3. Razor Components. Twice as slow as option 2. Consumes memory 2-5 times more than option 2.

ps. To call the Razor Component from .cshtml I use the following code
@(await Html.RenderComponentAsync<RazorLib.Views.Emails.v1.Shared.RazorComponents.Performance>(RenderMode.Static, new { Text = "qwerty"}))

@ghost ghost locked as resolved and limited conversation to collaborators Dec 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-mvc-razor-views Features related to the Razor view engine for Razor pages and MVC views ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Status: Resolved
Projects
None yet
Development

No branches or pull requests

2 participants