Developer forum

Forum » Templates » Razor partial views and helper functions

Razor partial views and helper functions

Kim Pilgaard
Reply

Until now our frontenders have utilized @Include quite a bit. However I would like for them to get the most out of intellisense, which isn't optimal with @include. And due the way @include works we have encountered some issues with razor/html context, as well as sharing variables/models in a meaningful way.

For that reason I was looking into the alternatives which would normally be used in razor templates. I have found 2 examples which doesn't seem to work out of the box in Dynamicweb razor.

1) Partial views. This seems to be the standard for larger sections of reusable code. However as far as I can tell @Html is not avaliable out of the box in a Dynamicweb razor template. Is this correct? And if yes will it become avaliable?

2) Helpers. This seems to be a good solution for smaller sections of reusable code. I have followed the method as presented here: https://docs.microsoft.com/en-us/aspnet/web-pages/overview/ui-layouts-and-themes/creating-and-using-a-helper-in-an-aspnet-web-pages-site as on a Dynamicweb website. However this does not appear to work on Dynamicweb, is this correct? And if yes will it become avaliable.


Replies

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Kim,

 

You are not alone!

 
Kim Pilgaard
Reply

Hi Dynamicweb,

I would really like to hear your thoughts on this.

 
Kim Pilgaard
Reply

@Dynamicweb if you have an alternative solution to avoid the issues we are experiencing with "include" then I would love to hear it. It would make it a lot easier for me to advice our frontenders on the correct way to structure their code.

 
Morten Bengtson Dynamicweb Employee
Morten Bengtson
Reply

My thoughts...

Partial views

We could add a RenderPartial method to view model templates. This would be implemented on the ViewModelTemplate base class.
Then you could do something like this and get full intellisense inside the partial views...

<div>
    @* Use current model *@
    @RenderPartial("partials/page.cshtml") 
 
    @* Use any other model that inherits from ViewModelBase *@
    @RenderPartial("partials/page-area.cshtml"this.Model.Area)
    @RenderPartial("partials/page-properties.cshtml"this.Model.PropertyItem)
    @RenderPartial("partials/page-cart.cshtml"this.Model.Cart)
</div>

See attached "proof of concept".

Custom helpers

I haven't found a nice solution to this yet. You can implement a stactic class and either place it in an assembly or drop it in the /App_Code folder.

<div>
    @MyStaticClass.DoStuff("something")
</div>

 

Let me know what you think

Best regards,
Morten

 
Nicolai Pedersen
Reply

Hi Kim

Also see my attachments. I created the App_Code folder and added a helpers razor file there. That will give me intellisense.

Then I use Dynamicweb includes to make sure the template is actually loaded when running in Dynamicweb context.

All of this requires a VS project that will parse the helpers in app_code to provide the intellisense.

BR Nicolai

Capture.PNG Capture1.PNG
 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Doing this with App_Code is nice and gives great IntelliSense in Visual Studio. However, it also means these templates can no longer be edited from the backend. Would it be possible to move them to a sub folder of App_Code like App_Code\Templates and then virtualize this folder into the File Archive as a Global Templates folder or something like that?

 
Nicolai Pedersen
Reply

Maybe a little web.config magic can do the trick?

https://msdn.microsoft.com/en-us/library/54dwfbb7(v=vs.100).aspx

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

I can't get this to work end-to-end, because when DW cannot interpret MyCustomHelpers. In other words:

  • I get intellisense in VS
  • I upload all files to the webserver
  • I get 
    The name 'something' does not exist in the current context

 

Can you confirm it works for you? If so, what could I be doing wrong?

 

We got it working internally from end-to-end, but it's a bit cumborsome to maintain.

 

Best Regards,

Nuno Aguiar

 
Nicolai Pedersen
Reply
This post has been marked as an answer

I get your point.

I've added an overload to the @Include where you can specify the "namespace" of the helpers - in this setup just the name of the file. That will make the HelperTest.Method() syntax work also on runtime. TFS#41741 released with next hotfix.

Also we added the RenderPartial as suggested by Morten, TFS#41664, also released with next hotfix.

Let me all hear how it works when you get it installed.

BR Nicolai

Capture.PNG
Votes for this answer: 1
 
Kim Pilgaard
Reply

@Morten I like your way of thinking. However as far as I can tell the standard is a HtmlHelper class which is accessable via @Html. 
Since the HtmlHelper also has functions for rendering partial views this would also solve the issue. However it would solve it in a way which 
makes the DW razor engine closer to the one used elsewhere.

@Nicolai The reason intellisense works when you add an App_Code folder is because it is supposed to be available. Is there a technical limitation in DW which 
prevents this from being possible without the usage of includes?

 
Nicolai Pedersen
Reply

Hi Kim

@Html and App_code/Helpers.cshtml are MVC conventional stuff - and not System.Web.Razor stuff. And Dynamicweb template engine is just Razor. So things are 'look-a-like'. So basically there is a lot of MVC magic that is not available in our context.

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

That is awesome news. The only bad thing about it is that I have to wait until next Tuesday for it cheeky

If you happen to have an early-release I am interested and giving it a test-drive on my local machine.

 

Thank you.

Nuno Aguiar

 
Nicolai Pedersen
Reply

Find it attached for 9.3

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

I am testing the dll, but it looks like it only takes an 'object' as parameter and does not take a string (just like you screen dump suggested). Can you confirm?

 

Best Regards,

Nuno

 
Nicolai Pedersen
Reply

Correct. Coming from the top base class in the stack. I've added a couple of overloads to RazorTemplateBase to give you the right intellisense.

Thanks, Nicolai

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

That sounds great. Can you once aganin get me an early release?

 

Nuno Aguiar

 
Nicolai Pedersen
Reply

Updated version attached.

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

As soon as I put that new dll I the the error in attach. Something else must be going on. Can you take a look?

 

Best Regards,

Nuno

 

IncludeIntellisenseError.jpg
 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

Did you see this post? And you keep sending me the Dynamicweb.dll, but after I took a closer look, shouldn't you actually be sending a new version of RazorEngine.dll? That's where I see the @Include method being used when I use a decompiler tool.

 

Best Regards,

Nuno Aguiar

 
Kim Pilgaard
Reply

Hi Nuno,

The RazorEngine.dll isn't made by Dynamicweb so Nicolai has no reason to send you this unless they have needed to update the RazorEngine to perform their changes. 

Still early monday morning but the error you are seeing makes me think you need a new Dynamicweb.Security.dll

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Kim,

 

That makes sense to me, but I got confused because from within RIder (I assume using VS with ReSharper or another decompiler will get you the same thing), points to this

/// <summary>Includes the template with the specified name.</summary>
/// <param name="cacheName">The name of the template type in cache.</param>
/// <param name="model">The model or NULL if there is no model for the template.</param>
/// <returns>The template writer helper.</returns>
public override TemplateWriter Include(string cacheName, object model = null)
{
  return base.Include(cacheName, model ?? (object) this.Model);
}

 

And it says to come from here:

// Decompiled with JetBrains decompiler
// Type: RazorEngine.Templating.TemplateBase`1
// Assembly: RazorEngine, Version=3.4.1.0, Culture=neutral, PublicKeyToken=9ee697374c7e744a
// MVID: 8627FECB-ADD3-475B-A468-7594D70B7E0F
// Assembly location: C:\Projects\Dynamicweb\Sites\rizzo9.localtest.me\Application\bin\RazorEngine.dll

using RazorEngine.Compilation;
using System.Dynamic;

namespace RazorEngine.Templating
{
...
}

 

Anyway, we'll see when Nicolai can reply or we'll just have to wait for the hotfix tomorrow :)

 

Best Regards,

Nuno

 
Nicolai Pedersen
Reply

Hi Nuno

Try getting the 2.5 version of security from MyGet: https://www.myget.org/feed/dynamicweb-packages/package/nuget/Dynamicweb.Security

 
Kim Pilgaard
Reply

Hi Nuno,

Nice to know that I am not the only one using Rider and dotpeek :)

Looked at it briefly. Are you using ViewModelTemplate or RazorTemplateBase? As far as I can tell this was only added to RazorTemplateBase.

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

I got it working. Thanks. I will try the web.config approach to have the files available through the backend.

 

Hi Kim,

You're not alone :) Rider rocks!

I am using the RazorTemplateBase. Otherwise we'd only get intellisense to a fraction of the templates.

 

Best Regards,

Nuno Aguiar

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

The web.config magic trick you mentioned does not seem to work:

  • As far as VS is concerned the files needs to be under App_Code
  • If the files are not within /Files they are not accessible from the backend

 

Do you have another idea how to get around this?

 

Best Regards,

Nuno Aguiar

webConfigSubFolders.jpg
 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

Additionally when a helper has some DW methods we run into more problems. We tried to solve it in a number of ways, but none seem to be simple enough and/or that would not work end-to-end.

 

Although the example in attach seems kind of dumb and easy to fix, a better example is:

  • You have a helper to takes multiple parameters
  • Within the helper we need to call GetString, GetBoolean, GetInteger, Translate,...

 

Can you think of a way to solve for this?

 

Best Regards,

Nuno Aguiar

 

NonStaticMethodInStaticContenxt.jpg
 
Kim Pilgaard
Reply

Hi Nuno,

Have you tried passing the RazorTemplateBase object as an argument to the helper function? In your case I guess that would be RenderStandardParagraphHeading( this ) in the template. 

Otherwise I would try passing whichever variables the helper function needs from the template to the helper.

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Kim,

 

That would require me to go through +120 helpers and functions and all of it's usages. I was hoping there could be a better way, which would not involve changing the current implementation (although in a way I have to already to assign the proper namespace when requesting a helper).

 

This also means it would make projects currently in-flight very hard to upgrade. Can anybody see a way to achieve this?

 

Best Regards,

Nuno Aguiar

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

To overcome the issue of the App_Code folder becoming unreachable within Dynamicweb's backend, would it be possible to have the File Manager expose it within Template (folder) or as a sibling?

 

  • Having that accessible ensures we can still edit all templates and files within the backoffice
  • To overcome the non-static issue it's a matter of adding the template as a parameter, and that we can do

 

Does this make sense?

 

Nuno Aguiar

 

You must be logged in to post in the forum