3

I have a server side Blazor application. There are two options when it comes to writing a razor page under Blazor: Design code and C# code in one ".razor" file and separated design and code files as ".razor" and ".razor.cs" files. The problem is that Visual Studio does not fully support intellisense in razor pages but you can always put your code to a separate file and use full intellisense support. Here is a minimal sample razor page with the code block in it:

@page "/minimalsample"
<h3>MinimalSample</h3>

<MatChip Raised="true" @onclick="@OpenUp" @ref="SampleMenuButton" Label="Actions" LeadingIcon="cloud_download"></MatChip>

<MatMenu @ref="SampleMenu">
    <MatList SingleSelection="false" TwoLine="false">
        <MatListItem OnClick="@Format_Clicked" Style="height: auto">
            Format C: Drive
        </MatListItem>
        <MatListItem OnClick="@Shred_Clicked" Style="height: auto">
            Shred files
        </MatListItem>
    </MatList>
</MatMenu>

<br />

@ActionText

@code {

    private BaseMatMenu SampleMenu;
    private BaseMatChip SampleMenuButton;
    private string ActionText;

    private void OpenUp()
    {
        SampleMenu.OpenAsync(SampleMenuButton.Ref);
    }
    private void Format_Clicked()
    {
        ActionText = "Formatting C: Drive...";
    }
    private void Shred_Clicked()
    {
        ActionText = "Shredding user files...";
    }

}

This code is working correctly. It opens up a menu when I click the button and menu items are also working fine. I decided to separate code and design files in order to be able to use intellisense features of Visual Studio (2019) and now I'm getting warnings saying:

Warning CS0649 Field 'MinimalSample.SampleMenu' is never assigned to, and will always have its default value null

warning messages

The ".razor" page is as follows:

@page "/minimalsample"
@namespace Pages
<h3>MinimalSample</h3>

<MatChip Raised="true" @onclick="@OpenUp" @ref="SampleMenuButton" Label="Actions" LeadingIcon="cloud_download"></MatChip>

<MatMenu @ref="SampleMenu">
    <MatList SingleSelection="false" TwoLine="false">
        <MatListItem OnClick="@Format_Clicked" Style="height: auto">
            Format C: Drive
        </MatListItem>
        <MatListItem OnClick="@Shred_Clicked" Style="height: auto">
            Shred files
        </MatListItem>
    </MatList>
</MatMenu>

<br />

@ActionText

And the code file ".razor.cs" is:

using MatBlazor;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Pages
{
    public partial class MinimalSample : ComponentBase
    {
        private BaseMatMenu SampleMenu;
        private BaseMatChip SampleMenuButton;
        private string ActionText;

        private void OpenUp()
        {
            SampleMenu.OpenAsync(SampleMenuButton.Ref);
        }
        private void Format_Clicked()
        {
            ActionText = "Formatting C: Drive...";
        }
        private void Shred_Clicked()
        {
            ActionText = "Shredding user files...";
        }

    }
}

I had to change button and menu references to have some default values (just to make compiler happy!).

    private BaseMatMenu SampleMenu = new BaseMatMenu();
    private BaseMatChip SampleMenuButton = new BaseMatChip();
    private string ActionText = "";

I know that this is not necessary and it is working without the new operators. Yet compiler is still complaining that variable "ActionText" is assigned but its value is never used.

I want to get rid of the warnings in a proper way (moving code to .razor page is not an option here). What can I do to get rid of these warnings? Is there a chance that this is a compiler bug?

Update:

@NikProtsman provided a working solution. I just removed the partial modifier and changed the name of the class definition in ".razor.cs" from

public partial class MinimalSample : ComponentBase

to

public class MinimalSampleBase : ComponentBase

I changed also the private modifiers to protected

...
...
    public class MinimalSampleBase : ComponentBase
    {
        protected BaseMatMenu SampleMenu;
        protected BaseMatChip SampleMenuButton;
        protected string ActionText;

        protected void OpenUp()
        {
            SampleMenu.OpenAsync(SampleMenuButton.Ref);
        }
        protected void Format_Clicked()
        {
            ActionText = "Formatting C: Drive...";
        }
        protected void Shred_Clicked()
        {
            ActionText = "Shredding user files...";
        }
    }
...
...

Later I've changed the ".razor" page like this

@page "/minimalsample"
@namespace Pages
// added this line
@inherits MinimalSampleBase
...
...

Now I'm not getting warnings and my code is running as expected.

Celal Ergün
  • 955
  • 2
  • 14
  • 30

2 Answers2

3

The documentation shows using the Partial Class approach, but I've always had better luck using an inheritance model instead. For your .razor.cs file, you might try calling the class a base: public class MinimalSampleBase : ComponentBase and then in your .razor file, add @inherits MinimalSampleBase. All your private fields and methods that you need to use on the markup page should now be protected instead, but backing fields and support methods should still be marked private. The base class now becomes a "View Model" and still gets full VS Intellisense and refactoring support, and you get all the benefits of the Code Behind approach, and hopefully in your case it will make those compiler warnings go away.

I've also found the Partial Class approach to cause problems for anything where I need to implement interfaces, as in setting up event subscriptions to a service and using IDisposable to unsubscribe on teardown. The inheritance model works perfectly however.

Give this a shot and report back please, I think it will help but I'm very curious to find out for sure.

Nik P
  • 2,693
  • 9
  • 21
  • Thank you for the answer. It seems like its working as it should be. I will post the latest source code in case anybody needs this solution. – Celal Ergün Apr 28 '20 at 07:15
1

Looks like we need to wait for .NET 5: "This looks to be an issue with how we generate the skeletons of our Blazor files in our pre-build step because that pre-build step removes all Razor content other than what's in @functions / @code. This would technically be fixed by source generators but those are on the cutline for .NET 5."

https://github.com/dotnet/aspnetcore/issues/20137

Edit: I confirm that the problem is solved in .NET 5. It is working without inheritance/protected properties etc.

Celal Ergün
  • 955
  • 2
  • 14
  • 30