Saturday 11 July 2020

Adding live reloads developing Asp.Net Mvc Core razor views

To add live reloading when developing Asp.Net Core Views, it is recommended to upgrade to .Net Core 3.1. This makes it easier to add in the Nuget package for recompilation. In case you have a .Net Core 2 app, follow the MSDN guide here: https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio After the app runs as .Net Core 3.1, run the following (procedure below is tested okay with VS 2019 and Chrome as the browser 'linked' to the reloading: Edit the .csproj file by selecting the project and right clicking and selecting Edit project file in VS 2019. Past in these two Nuget package references and run dotnet restore, then dotnet build and finally dotnet run.

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.5" />
    <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.2.0" />
  </ItemGroup>

The runtime compilation and Browserlink should both be added. The first will rebuild your edited razor views (cshtml) and BrowserLink reloads your browser while debugging, after the razor view is updated. Also download this Visual Studio Extension, "Browser reload on save": https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BrowserReloadonSave You will have to close all Visual Studio processes to start installing Mad Kristensen's browser extension. In your Startup class you should inside ConfigureServices add these two lines, specifying AddRazorRunitmeCompilation:
        services.AddRazorPages().AddRazorRuntimeCompilation();
        services.AddControllersWithViews().AddRazorRuntimeCompilation();
And finally at the top of the Configure method in the Startup class add in BrowserLink. Note, add this at the top of the Configure method such that the pipeline is adding BrowserLink correct.
  if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
Now, just start up your app with F5 and start editing a razor file. If all was set up correct, you should now see your razor view reload in the Browser. This makes it easier to edit and adjust razor views!

Monday 29 June 2020

Adding Bootstrap 4 to Asp.Net Core MVC solution

To add Bootstrap 4 or newer to an Asp.NET Core MVC Solution, you can do this in the following manner if you use Visual Studio 2019 and .Net Core 3.1. Or at least have access to the 'Manage Client-side Libraries' functionality. Bootstrap is not supported in Nuget and definately not for .Net Core apps, so you need to add it manually using this. The Manage client-side libaries in Visual Studio adds a libman.json file. This is the Library Manager json file, similar to NPM based solutions package.json. Now add the following into libman.json:

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
    {
      "library": "twitter-bootstrap@4.2.1",
      "destination": "wwwroot/lib/bootstrap",
      "files": [
        "js/bootstrap.bundle.js",
        "css/bootstrap.min.css"
      ]
    },
    {
      "library": "jquery@3.3.1",
      "destination": "wwwroot/lib/jquery",
      "files": [
        "jquery.min.js"
      ]
    }
  ]
}

This adds Bootstrap 4.2.1 and Jquery 3.3.1 into wwwroot lib folders for each library. Now in your _Layout.cshtml file (or the file you use as your Layout file), just drag bootstrap.min.css file and bootstrap.bundle.js files into that razor file. After you restart the solution, you should have Bootstrap 4 available into your Asp.Net Core MVC app! And if you want to add client side libraries using a GUI, select your project and choose then via right click Add->Client side library. Here you can search for client side libraries.

Wednesday 17 June 2020

Multiple enum values set to same value codefix for VS

I created a new extension in Visual Studio today! The UniqueEnumValueFixer vs extension is now available here! https://marketplace.visualstudio.com/items?itemName=ToreAurstadIT.EXT001 The extension is actually a Code Fix for Visual Studio. It flags a warning to the developer if an enum contains multiple members mapped to the same value. Having a collision with values for enum causes ambiguity and confusion for the developer. An enum value has not got a single mapping from enum member to integer value. Example like this: Here we see that iceconverted is set to Fudge, which is the last of the colliding valued enum members. This gives code which is not clear and confusing and ambiguous. It is perfectly valid, but programmers will perhaps sigh a bit when they see enums with multiple members mapped to same value. The following sample code shows a violation of the rule:

    enum IceCream
    {
        Vanilla = 0, 
        Chocolate = 2,
        Strawberry = Vanilla,
        Peach = 2
    }

Here, multiple members are mapped to the same value in the enum. Strawberry and Vanilla points to the same value through assignment. And Peach is set to same value as Chocolate. The code fix will show enums containing the violation after compiling the solution in the Errors and Warnings pane of Visual Studio.

   public override void Initialize(AnalysisContext context)
        {
            // TODO: Consider registering other actions that act on syntax instead of or in addition to symbols
            // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Analyzer%20Actions%20Semantics.md for more information
            context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);

        }

        private static void AnalyzeSymbol(SymbolAnalysisContext context)
        {
            try
            {
                var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
                if (namedTypeSymbol.EnumUnderlyingType != null)
                {
                    var valueListForEnum = new List<Tuple<string, int>>();
                    //Debugger.Launch();
                    //Debugger.Break();
                    var typeResolved = context.Compilation.GetTypeByMetadataName(namedTypeSymbol.MetadataName) ?? context.Compilation.GetTypeByMetadataName(namedTypeSymbol.ToString());
                    if (typeResolved != null)
                    {
                        foreach (var member in typeResolved.GetMembers())
                        {
                            var c = member.GetType().GetRuntimeProperty("ConstantValue");
                            if (c == null)
                            {
                                c = member.GetType().GetRuntimeProperties().FirstOrDefault(prop =>
                                    prop != null && prop.Name != null &&
                                    prop.Name.Contains("IFieldSymbol.ConstantValue"));
                                if (c == null)
                                {
                                    continue;
                                }
                            }

                            var v = c.GetValue(member) as int?;
                            if (v.HasValue)
                            {
                                valueListForEnum.Add(new Tuple<string, int>(member.Name, v.Value));
                            }
                        }
                        if (valueListForEnum.GroupBy(v => v.Item2).Any(g => g.Count() > 1))
                        {
                            var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0],
                                namedTypeSymbol.Name);
                            context.ReportDiagnostic(diagnostic);
                        }
                    }
                }
            }
            catch (Exception err)
            {
                Console.WriteLine(err);
            }

        }

The source code is available on Github here: https://github.com/toreaurstadboss/UniqueEnumValuesAnalyzer