Creating a new Blazor project for components and pages - c#

I am creating a Blazor WASM project and would like to separate my Blazor components and pages from the hosting model.
This would make it easy to change hosting model to for example a Server based application, where I just would need to create a new project and reference my components and pages library.
It would also allow me to separate my components and pages library from specific implementations (services or data models) by using interfaces and DI. Only the hosting project would need to know my implementation details.
The issue is that I cannot get it to work properly with visual studio. I have tried to create a .NET Standard 2.1 project for my components/pages but then I cannot create new razer components. Do I need to configure the project in some way? How should I make my shared components/pages library?

You need to select a Razor Class Library template:
It will contain a wwwroot directory where you can put your images, css or other static web resources. You can also use Library Manager (libman.json) if you add the json.
More information here: https://learn.microsoft.com/en-us/aspnet/core/blazor/class-libraries?view=aspnetcore-3.1&tabs=visual-studio

Related

Run Blazor WASM as Blazor Server-Side

Problem
Blazor WASM could've been easily preferred over Blazor Server-Side without its downsides development-wise. Currently, Blazor WASM doesn't support a full-featured debugging experience and has a very slow startup. This slows down development much more than with Blazor Server-Side. Though I honestly personally think that the debugging experience slows down the development much more than the slow startup.
Proposed Solution
NOTE: I included the "proposed" word in there because I'm not sure about the downsides that this solution can cause, so feel free to comment on my answer below.
The solution is to simply create an additional Blazor Server-Side project then reference the Blazor WASM project to the Blazor Server-Side project. Afterwards, add some tweaks to the Startup and the _Host.cshtml of the Blazor Server-Side to properly use the Blazor WASM razor files and the wwwroot files. See my proposed answer below for a step-by-step explanation for this solution.
In simpler terms, this solution just adds and configures the Blazor Server-Side project without making any changes and any significant code duplication to the Blazor WASM project.
NOTE: In this example, I'm using Visual Studio 2019 16.7.2 and the version of the templates are currently at 3.1.8
Create a Blazor WASM project. Either the ASP.NET Core Hosted or the Standalone option will work fine but they will have different configurations later that will be discussed. The rest of the options won't have any effect. In this example, I'll go with the ASP.NET Core Hosted to explain later about having API Controllers. Also create the Blazor Server-Side project afterwards.
As of this moment, your project structure should be similar to the first screenshot below.
Delete the highlighted items in the Blazor Server-Side project shown in the second screenshot below.
Reference the Blazor WASM project to the Blazor Server-Side project.
ASP.NET Core Hosted - Reference both the BlazorWasm.Client & BlazorWasm.Server project.
Standalone - Reference the single Blazor WASM project as is.
Go to the Startup class of the Blazor Server-Side project. In the ConfigureServices(), remove the WeatherForecastService together with the BlazorServer.Data namespace then add a service for the HttpClient to be used by the razor files from the Blazor WASM project.
services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(sp.GetRequiredService<NavigationManager>().BaseUri) });
NOTE In production, I don't suggest creating an instance of the HttpClient. Use the IHttpClientFactory instead. Visit this article Use IHttpClientFactory to implement resilient HTTP requests.
For ASP.NET Core WASM Projects
In the Configure(), map the controllers' endpoints. This will use the controllers in the X.Server/BlazorWasm.Server project.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
...
});
Go to the _Host.cshtml in the /Pages folder of the Blazor Server-Side project. Change the reference of the css/site.css to css/app.css since the filenames for the main css file for the Blazor WASM project are different.
<link href="css/site.css" rel="stylesheet" /> <!-- Previous -->
<link href="css/app.css" rel="stylesheet" /> <!-- New -->
Lastly, change the App in the type attribute of the component tag and refer to the App razor class file in the Blazor WASM project. In this example, the App class is found in the BlazorWasm.Client project:
<component type="typeof(App)" render-mode="ServerPrerendered" /> <!-- Previous -->
<component type="typeof(BlazorWasm.Client.App)" render-mode="ServerPrerendered" /> <!-- New -->
That's it! When you run the Blazor Server-Side project, it should load without the "Loading ..." text.
No changes made to the Blazor WASM project(s) and no significant code duplication made.
The only things to change are the references and the launchSettings.json & appsettings.json.
As for the configurations in the Startup for the Blazor Server-Side, you can just create extension methods in the Blazor WASM project(s) and use them in the Blazor Server-Side project.
NOTE: I honestly think this is ideally(?) only for debugging during development since the WASM razor files won't fully utilize the capability of a true Blazor Server-Side because it would still use HTTP Requests.
Hoping for feedbacks down below! :DD
I would suggest an alternate way. There are other drawbacks to referring to WASM project from a server project, but personally I think it is an architecturally inelegant solution.
There are some critical areas where Blazor Server and WASM differ :
Authentication: Blazor server allows you to customize access to specific areas at runtime. In WASM, the authorization happens in one go and the app code is sent in its entirety.
Database is access : Blazor server allows direct access to EF core entities (since the code executes only on the server). In blazor, it is realistically not possible to access any database directly. It is also highly discouraged because you would be sending connection strings to the client. Hence you need to write a separate web API for data access.
3.Settings files : you can have as many settings files in server-side blazor. Client side blazor loads only appsettings.json by default. A special mechanism is required to include multiple .json files.
Therefore, for most applications (and definitely the ones that require database access) you will not be able to share 100% codebase between WASM and Server-side.
Here is what you should do instead:
For the points mentioned above, (auth, but mostly db access), create a data access service dependency (say IDataAccessLayer).
One implementation will access the database directly (to be used in server side)
The other implementation will access the database through an HttpClient (to be used in blazor WASM).
Now, put your entire app in an RCL. Call it "BlazorAppRCL". This RCL obviously does not have Startup.cs and Program.cs
Create a project for server and client specific db access implementation
Now, you have the following set of projects:
For Server Side:
BlazorServer (has only settings + Program.cs + Startup.cs). It refers to the RCL + Server specific implementation of IDataAccessLayer
For hosted WASM:
BlazorWebAPI : For database access, it has API to access database
BlazorClientDAL : WASM specific implementation of IDataAccessLayer
BlazorWASM : Blazor WASM project
All three refer to your BlazorAppRCL.
The crux is to use DI/ inversion of control pattern to address the divergence between WASM and Server.
This way, you can have a both instances WASM and Server instances with minimal code divergence. Note that the WASM WebAPI can simply use the server side blazor's implementation od IDataAccessLayer as it is. So beyond API related overhead, additional coding is not necessary.

Configuring AutoMapper in Multiple Projects

I currently have built an MVC solution which has a web project (controllers/views/scripts), services project (business layer, builds view models), and repositories project (data access layer).
I have used AutoMapper in my projects in the past and am trying to configure AutoMapper in this solution. Normally, I configure all of my maps in MapperConfig.cs which is called in Global.asax.cs.
My Problem is that the web project which is where I normally configure AutoMapper only has reference to the services project and the services project only has reference to the data project. So, when I go to configure my maps as I normally would, I am unable to define maps for the data project due to the web project not having a reference to the data project. I need a way to configure my data access layer maps without adding a reference for the data project to the web project.
The project dependency diagram would look like the following:
Web Proj --> Services Proj --> Data Proj
How can I overcome this?
There is no need to have a single mapping registration file across all projects, especially that you say that you don't have any cross-cutting types.
The simplest way would be to define a configuration file per project, and have those configurations call each other, repeating the layered dependencies of your assemblies, like below:
Global.asax.cs --> WebProjMapRegistrations.Register()-->ServicesMapRegistrations.Register()-->DataMapRegistrations.Register()
Alternatively, you could use the Assembly Scanning for auto configuration
As described by #Jimmy Bogard, when you run your web app, all assemblies of your application will eventually get loaded into your application domain - so you can get all the profiles from all the assemblies and add them to mapper config: How to Initialize AutoMapper Profiles in referenced project DLLs in ASP.Net webapp
Yet another alternative approach, that works for ASP.NET apps can be found here:
Where to place AutoMapper map registration in referenced dll
The way I've handled this in some ASP.Net MVC projects, is by using AutoMapper Profiles.
You create separate mapping Profiles that handle creating the Mappings for objects in that Project/Assembly.
You then add the profiles to the overall configuration manually, or you can use Reflection/Assembly scanning to automatically load the profiles.

Is it possible to make separate dlls with MVC project?

We have a big project developed in Asp.net MVC5. Our models and business logic are defined in separate class libraries. Now we need to add another module to an existing project but we want a separate dll.
This module also shares the most javascripts, css files and other files. That is the reason we don't want to separate MVC project.
Is there any why we can create separate dll for module basis. so we don't want deploy or touch other dlls.
From your description, you say that the projects share CSS and JS files. This leads me to believe you are talking about a separate MVC website (possibly part of the larger corporate website). This can be easiest with the use of Areas. If you are not familiar with Areas, please read the following: https://msdn.microsoft.com/en-us/library/ee671793(VS.100).aspx
Of course using Areas will require you to deploy the whole site everytime one of the areas change, and you have mentioned that you want to avoid doing so.
If you don't want to use areas, and instead want to create another MVC project in the same solution, you can do that easily too. You can right click on the solution, add new project > ASP.NET web application > MVC to add the project. To share JS and CSS files between these two MVC projects, you will have to create a new solution folder (right click solution > Add new solution folder), and move your resource files to that folder. Inside each MVC project in your solution, you will add existing items and select those js/css resource files. This way if you change the css file, it will be reflected in both the projects.
For more information, read the following:
How do you share scripts among multiple projects in one solution?
Yes you can, just add the logic classes to other class library project (you can have as many as you want), then add references of those class librarys to the mvc project.
Don't forget to import the classes after in your code
Edit: I'm assuming you are using Visual Studio, if yes, you can go to File -> Create Project, this will create another project in the same solution.
I don't know whether you tried with Managed Extensibility Framework (MEF) or not.. this framework works as you required ... I think below link will help you more
ASP.NET MVC Extensibility with MEF
How to integrate MEF with ASP.NET MVC 4 and ASP.NET Web API
http://www.codeproject.com/Articles/167321/MEF-with-ASP-NET-Hello-World
Other people have posted answers regarding the use of Areas. Areas are great and good and helpful. They really benefit the project structure.
This module also shares the most javascripts, css files and other file
The title of your question is about .dlls, but I suspect the client-side resources are the main concern.
If you consider your webapp as having two distinct parts: server-side and client-side, you can use appropriate strategies to modularize each. Areas a great for organizing server-side code, but don't help the front-end.
Front-end package management options have expanded for ASP.NET 5. In addition to the traditional NuGet package manager, Bower and NPM are now supported. For example, consider how this article demonstrates installing jQuery via NPM. Here's another good article about setting up NPM, Bower, and Gulp in Visual Studio.
What to do: Take your existing client-side code and make a custom NPM or Bower package, and then use that package from one or more Asp.NET projects.
I can suggest you two ways to organize your multi-module project.
Option 1 - Create Area per module, within same web project
One way to do it is, create separate Area within the same MVC project. So each module will have a separate area, with separate controllers, views, scripts etc. But,
(1) This will still create a single dll for the whole MVC project
(2) Sharing files across areas might not be very easy in some scenarios (you can keep all the scripts for all the modules in one shared directory though)
Option 2 - Create class library per module, merge after build
Another way is to create a single class library project per module. Add reference to the System.Web.Mvc and other libraries so that it can have controllers etc. Create your own views, scripts and other folders and populate with files as you need them.
Now, all your modules will build as separate projects, with the dll file and the javasvripts, htmls, csss, images etc. To make them all work as a single web application you can create a (only one) MVC web project, which will go to the IIS virtual directory and will be published as web.
To use all your separate modules from the same web, you can write post build events in all those libraries to copy the artifacts (dll, scripts etc.) into the main web, into corresponding folders (dll to \bin, javascript to \scripts etc.). So, after successful build, all the artifacts are available in the same web project, and that can be deployed as a single web with all the modules. Your post build scripts should look something like this
XCOPY "$(ProjectDir)$(OutDir)*.*" "$(ProjectDir)..\YourMainWebDirectory\Bin\" /Y
XCOPY "$(ProjectDir)Content" "$(ProjectDir)..\YourMainWebDirectory\Content\" /S /Y
XCOPY "$(ProjectDir)Scripts" "$(ProjectDir)..\YourMainWebDirectory\Scripts\" /S /Y
XCOPY "$(ProjectDir)Views" "$(ProjectDir)..\YourMainWebDirectory\Views\" /S /Y
XCOPY "$(ProjectDir)Images" "$(ProjectDir)..\YourMainWebDirectory\Images\" /S /Y
Now,
(1) You have separate dlls for separate modules
(2) Can directly share scripts and other files, as they will be in same location (after build)
(3) If you decide to remove a specific module from the web, just remove the post build event from that module (project) without affecting anything else. You can add that back at any time you please.
Your overall solution will look like
Module01.csproj => post build copy to main
\Controllers
\Scripts
\Views
\Contents
\Images
Module02.csproj => post build copy to main
\Controllers
\Scripts
\Views
\Contents
\Images
Models.csproj
\...
Application.csproj
\...
Main.Web.csproj => main web application hosted in IIS
\Controllers
\Scripts
\Views
\Contents
\Images

.Net Architecture: Implement asp.net identity as separate project inside solution

I have a custom MVC 5 solution separated into 3 main projects, Data, Admin, and Public.
I need to add .NET Identity and it's related utilities.
I have read articles showing how to add it to an existing MVC project and I think I can handle that (basically add the dependencies/files).
My question is:
Does it make sense to add a Security project and put the related Identity stuff in there and reference from Admin/Web projects?
Or should it reside in the Data project since that's already referenced and handles the data?
Either way, how to implement Identity across the two sites? The Identity will be modified to include extra info about the user so it might make sense to be a part of the Data project...?
Also, how do I implement the identity/security project so i don't need to add Identity to each project? (Architecture is where I really need the help here)
Basically, how would I implement security as a separate project using asp.net Identity?
When I build an app like this I typically am using Dependency Injection, and have a project that defines my services call it Core (perhaps in your case Data?). In this project I'll typically create a ISecurityService interface that defines methods needed to get the logged in user:
public interface ISecurityService {
string GetCurrentUserName();
}
You might want to return more than a string, an object etc.. Then in when asp.net project that defines the functionality for ASP.net Identity I simply create an ASPNetSecurityService that implements ISecurityService and wire this into my IOC / Dependency Injection system. That way any class that has a need to get this info Can just request a reference to ISecurityService and the IOC system will provide them the registered ASPNetSecurityService.
Alternatively you can use this same technique and place the ASP.net in a separate project if you wanted to, but by using this DI technique you can keep the Identity Stuff in asp.net mvc but still make use of the functionality from anywhere you like.
Does this help?
I did something similar this year and it works as I had anticipated. I have the ASP.Net Identity as a project of it's own. It has been customized as well for my company to handle all business logic/rules around authenticating users. I set it up as a NuGet package and can install it into any web project to handle authentication to a common user store. The consuming applications do not need to know any of the details about authentication. The developer just calls provided methods.
The way I started was I created a project from the default MVC template and made note of all the dependencies that identity needed. Then I included those dependencies in my custom NuGet package.
You can create your own NuGet packages using NuGet Package Explorer: https://npe.codeplex.com/
I checked my notes and here are all the dependencies the I wrote down (it's possible I overlooked one) that would need to be added to the NuGet Package:
NuGet Packages:
ASP.Net Identity Core
ASP.Net Identity Owin
ASP.Net Identity EntityFramework
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security.Facebook
Microsoft.Owin.Security.Google
Microsoft.Owin.Security.MicrosoftAccount
Microsoft.Owin.Security.Twitter
Add references:
System.Configuration
System.Web
System.Web.Helpers
Hope this helps!

linking silverlight class to web app

Have written all the code in a silverlight class library (dll) and linked this same library to my web app and silverlight app, is there a way to avoid the "Compiler Error Message: CS0433" or do I have to create a separate dll for the web app?
Error mostly occurs when XElement is called...
You need to create two projects, but can add the same CS file using Add Existing Item as a Link. http://msdn.microsoft.com/en-us/library/9f4t9t92.aspx explains it.
http://www.scip.be/index.php?Page=ArticlesNET28 is a nice read with related info.
Do you mean you are referencing a single dll from both the web app and the Silverlight app? I would have two versions of the dll (and two project files); one built for regular .NET (for use in the web app), and one for Silverlight; the main difference being the target framework and the references.
If you don't want to deal with having to maintain two project files (when you add classes etc), then you can use this trick to reduce this overhead.

Categories