Standalone Blazor app as a Razor Class Library - asp.net-mvc

Is it possible technically to have a full webassembly Blazor application as a Razor Class Library and then consume it in another ASP.NET project regardless of the consumer be MVC, Razor Pages, or Blazor app? Is it possible to define the routing within the Razor Class library?
I'm working on a project that is going to be published as a Nuget package. This package should be used in a variety of ASP.NET projects which are implemented as MVC, Razor Pages, or even Blazor.

I figured out how to get it running. I am using .NET 5.0.
First create a new Solution with a Razor Class Library project (Check the checkbox Support pages and views).
And create a MVC project.
In Startups.csadd the following:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddRazorPages();
services.AddServerSideBlazor();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Also make sure you have app.UseStaticFiles(); in your Configure method.
Then, in your Razor Class Library, you can copy and paste the Pages, Shared folders and all other razor files from the example Blazor webassembly project. Also don't forget the wwwroot css folder and add your own wwwroot folder to your RCL.
In the Pages folder also create a new cshtml file. This will be the entry point to your Blazor app.
Example code:
#page
#using PROJECTNAME
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Blazor WebAssembly Prerendered</title>
<base href="~/" />
<link href="/_content/PROJECTID/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="/_content/PROJECTID/css/app.css" rel="stylesheet" />
#*https://learn.microsoft.com/de-de/aspnet/core/blazor/components/css-isolation?view=aspnetcore-5.0#razor-class-library-rcl-support*#
<link href="/_content/PROJECTID/PROJECTNAME.bundle.scp.css" rel="stylesheet" />
</head>
<body>
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</app>
</body>
</html>
<script src="_framework/blazor.server.js"></script> <!--blazor.webassembly.js didn't work-->
The important parts are the <base href="~/" /> and the _framework/blazor.server.js.
If you don't map this page to be at the root, like #page "/" you have to make sure all the static content is mapped to the project-id correctly.
Also make sure the paths in the example projects NavMenu.razor are correct if you don't use / as the root. Has to be correct in the Razor Components too.
If you have problems with the _Imports.razor file, try adding the NuGet package Microsoft.AspNetCore.Components.WebAssembly
Also add the correct namespace for your shared folder, in the example project it's PROJECTNAME.Shared. Change it accordingly.
Here's a blogpost that helped me get things the right way: https://blog.joelving.dk/2020/02/reusable-ui-and-interchangable-hosting-models-in-blazor/

Related

Accessing CDN bundles on different ASP.Net MVC site

This is a follow-up question to this: ASP.Net MVC 5 - Deploy separate CDN site with bundled JavaScipt and CSS
I want to serve up my JavaScript and CSS bundles from a second ASP.Net website, so I have done the following.
Main website (ASP.Net MVC website that has not JS or CSS resources)
CDN website (ASP.Net MVC website that has all JS and CSS resources but not much else)
CDN Website Web.config extract
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
CDN Website Bundle Config
public static class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
}
}
Main Website Bundle Config
public static class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/Content/css", "http://[CDN website]/Content/css"));
//BundleTable.EnableOptimizations = true;
}
}
Main Website Layout View
<!DOCTYPE html>
<html>
<head>
#Styles.Render("~/Content/css")
</head>
<body>
#RenderBody()
</body>
</html>
Result
The HTML produced by the main website doesn't render the <link> tag for the CSS. However, if I turn on bundle optimizations (see commented out code in Main Website Bundle Config), then the <link> tag appears but looks like this:
<link href="/Content/css?v=" rel="stylesheet">
Navigating to http://[CDN website]/Content/css in the browser loads the appropriate CSS.
Navigating to http://[Main website]/Content/css in the browser loads an empty page.
Am I doing this the incorrectly? I don't want to reference the CDN website URL directly because I want the versioning that comes with the MVC bundler.
I ended-up using the following solution for the CDN website.
https://stackoverflow.com/a/26402383/2663033
The main website then used the appropriate MVC route of the CDN website for the style "href" and the script "src", which redirected to the appropriately versioned content or script bundle.

IIS Express with portnumbers

I have a ASP.Net MVC project in maintenance. Apparantely the IISExpress is adding portnumbers to localhost which is fine. except when the relative style sheet link does not contain the portnumbers?
How come the portnumbers are not added automaticaly? Seems pretty logical to me that when Visual Studio 2013 starts up it sends the browser to localhost with portnumber but when building the relative style sheet links it does not?
Guy
In view file:
<link rel="stylesheet" href="./metrouicss.css" />
After running in IISexpress:
<link rel="stylesheet" href="http://localhost//Templates/Design 2/metrouicss.css" />
Since IISexpress is running on port 42532 I would rather see it rendered like this:
<link rel="stylesheet" href="http://localhost:42532//Templates/Design 2/metrouicss.css" />
Sorry try this (I missed the rest of the path):
<link rel="stylesheet" href="~/Templates/Design 2/metrouicss.css" />
Or
If you are using MVC 5 you can use the BundleConfig class:
Public Sub RegisterBundles(ByVal bundles As BundleCollection)
bundles.Add(New StyleBundle("~/Templates/css").Include(
"~/Templates/Design 2/metrouicss.css"))
End Sub
And in view use the following in the tags:
#Styles.Render("~/Templates/css")

Visual Studio ASP.NET MVC Not Loading Local bootstrap.css

I installed bootstrap using nuget package manager and the css files are now in my /Content/ folder. However, when trying to reference them using:
<link rel="stylesheet" href="∼/Content/bootstrap.min.css" />
It doesn't work. But when referencing them using a CDN like:
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
It does work. I can't seem to figure out what is wrong as I have never had this problem before. I'm using an Empty template with MVC.
EDIT: After some playing around, I found that it was failing to load /%E2%88%BC/Content/bootstrap.css but after removing the tilda (~) it works fine. Anybody got any ideas?
This is not a correct path, it uses the tilda, which is used on the server when rendering links in server controls in asp.net.
Instead of this:
<link rel="stylesheet" href="∼/Content/bootstrap.min.css" />
Try this:
<link rel="stylesheet" href="#Url.Content("∼/Content/bootstrap.min.css")" />
Assuming that you are using Razor.
Alternatively, consider looking into style and script bundling that you get with new asp.net sites. Can be very useful.
Adding "app.UseStaticFiles()" to Startup.cs worked for me:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseBrowserLink();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
}
Now only Bootsrap 3 works with local links in .Net. Terrible. :( For 4, you must use CDN :
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

Getting Angular UI Directives for Bootstrap up and running with MVC

I am trying to get Angular UI Directives for bootstrap working with ASP MVC.
I have created a new, basic project and have used Nuget to add Twitter Bootstrap, AngularJS and UI Bootstrap.
I am registering these as bundles like so:
bundles.Add(new StyleBundle("~/Content/bootstrap")
.Include("~/Content/bootstrap.css")
.Include("~/Content/bootstrap-theme.css"));
bundles.Add(new ScriptBundle("~/bundles/angular")
.Include("~/Scripts/angular.js"));
bundles.Add(new ScriptBundle("~/bundles/angularUiDirectives")
.Include("~/Scripts/ui-bootstrap-{version}.js"));
My shared _Layout.cshtml page looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Testing Angular - #ViewBag.Title</title>
#Styles.Render("~/Content/css")
#Styles.Render("~/Content/bootstrap")
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
#RenderBody()
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/angular")
#Scripts.Render("~/bundles/angularUiDirectives")
#RenderSection("scripts", required: false)
</body>
</html>
So I have added the libraries for Angular UI directives, along with the dependencies listed here via Nuget, I am registering all of these libraries as bundles and then I am rendering these bundles on my shared master page.
So far so good, but then I get to the next instruction:
As soon as you've got all the files downloaded and included in your page you just need to declare a dependency on the ui.bootstrap module
What does 'declare a dependency' mean in regards to HTML and CSS? The page on github suggests I need to put the following somewhere:
angular.module('myModule', ['ui.bootstrap']);
Where do I put this, and when do I run it?
Thanks
I solve this by doing the following:
I added the following to the opening HTML tag of my master page (replacing appName with the name of your application):
ng-app="appName"
I created a seperate Javascript class which I called test.js, registered this as a bundle and added the following:
angular.module('appName', []);
angular.module('appName', ['ui.bootstrap']);
The first line defines the angular module, the second wires it up to the UI Bootstrap library, and you need both.
Updated code to register my bundles is below:
using System.Web.Optimization;
namespace MvcApplication2
{
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/Content/bootstrap")
.Include("~/Content/bootstrap.css")
.Include("~/Content/bootstrap-theme.css"));
bundles.Add(new ScriptBundle("~/bundles/angular")
.Include("~/Scripts/angular.js"));
bundles.Add(new ScriptBundle("~/bundles/angularUiDirectives")
.Include("~/Scripts/ui-bootstrap-tpls-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/test").Include("~/Scripts/Test.js"));
}
}
}
Here is the code for Test.js:
angular.module('appName', []);
angular.module('appName', ['ui.bootstrap']);
Here is the code for my master page:
<!DOCTYPE html>
<html ng-app="appName">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Testing Angular - #ViewBag.Title</title>
#Scripts.Render("~/bundles/angular")
#Scripts.Render("~/bundles/angularUiDirectives")
#Scripts.Render("~/bundles/test")
#Styles.Render("~/Content/bootstrap")
</head>
<body>
#RenderBody()
#RenderSection("scripts", required: false)
</body>
</html>
At this point we are fully setup with AngularJS, and Twitter Bootstrap and Angular Directives for Bootstrap in an ASP MVC application.

"Object reference not set to an object" when starting out with Cassette

I'm trying to get started with Cassette via NuGet. I'm having issues with it in my app so I rolled back and tried it in a new empty ASP.NET MVC 3 web application.
However, the problem persists. Following the documentation page "Easy to use", I simply can't get it to work. Here's the exception along with a bit of the stack:
"Object reference not set to an instance of an object."
[NullReferenceException: Object reference not set to an instance of an object.]
Cassette.CassetteApplicationContainer.get_Application() +6
Cassette.Views.Bundles.Reference(String assetPathOrBundlePathOrUrl, String pageLocation) +14
ASP._Page_Views_Shared__Layout_cshtml.Execute() in d:\Dave\Documents\Visual Studio 2010\Projects\CasetteTest\Views\Shared\_Layout.cshtml:2
System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +207
I simply followed the two steps in the documentation and this is what I get. What am I doing wrong?
This is what my _Layout.cshtml file looks like:
#{
Bundles.Reference("Scripts/jquery-1.5.1.min.js");
Bundles.Reference("Scripts/modernizr-1.7.min.js");
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
</head>
<body>
#RenderBody()
#Bundles.RenderScripts();
</body>
</html>
I figured it out.
I included the Cassette.Views package which does not create a default CassetteConfiguration.cs file that bundles each script and each css file in its own bundle. That's what triggered the NullReferenceException. In order to get it to work, you'll need to add the Cassette.Web package instead. In my defense, the package descriptions in the NuGet gallery are not clear and one is led to believe that the Views package is required for MVC and the other for WebForms.
The next problem was that I referenced the minified '.min.js' scripts which are not picked up by the bundler (it seems).
Cannot reproduce the issue.
4 simple steps allowed me to get a fully working prototype in less than 30 seconds:
Create a new ASP.NET MVC 3 project in Visual Studio
Install-Package Cassette.Web
Index.cshtml:
#using Cassette.Web
#{
Bundles.Reference("~/Scripts/jquery-1.5.1.js");
Bundles.Reference("~/Scripts/jquery-ui-1.8.11.js");
Bundles.Reference("~/Content/site.css");
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Web App</title>
#Bundles.RenderStylesheets()
</head>
<body>
<div>Hello World</div>
#Bundles.RenderScripts()
</body>
</html>
Hit Ctrl+F5 to run the project

Resources