Blazor Project structure / best practices

15,633

Solution 1

So I was diving into looking for more example projects and I came across a SPA Server Side Dapper application (https://www.c-sharpcorner.com/article/create-a-blazor-server-spa-with-dapper/). From what I can gather there, here, and everywhere else I look, adding a separate project for handling just CRUD operations seems to be more trouble than it's worth.

I will implement something along the lines of what is in that link and see how it goes. If anyone else is looking for some inspiration, there's some good examples here:

https://github.com/AdrienTorris/awesome-blazor#sample-projects

FWIW, every example seems to follow this path, just seems to go about it in slightly different ways (ORM use, folder names, etc.). This means I will need to add a lot more services (at least 20 in total), but if it's a complicated business application I just suppose that's the nature of the beast.

Happy coding!

Solution 2

I just created a new ASP .NET Core 3.1 project with 3 web apps: MVC, Razor Pages and Blazor.

NetLearner: https://github.com/shahedc/NetLearnerApp

I’m developing all 3 in parallel so that you can see similar functionality in all of them. I’ve extracted common items into a Shared Library for easy sharing.

The shared library includes:

  • Core items (Models and Services)
  • Infrastructure items (Db context and Migrations)

Here’s the corresponding blog writeup, which will be followed by an A-Z weekly series, which will explore 26 different topics in the next 6 months.

Hope the current version is useful for what you’re asking for. Stay tuned and feel free to make suggestions or provide feedback on the project structure.

NetLearner architecture

Solution 3

While working with three tier architecture, I see business layer will grow and some point of time become very messy and tightly couple.

I would recommend try Onion Architecture, its very popular and very similar to Clean Architecture.

I am sure you are looking some sample application to see how to keep each and every layer separate, what is best practices and best libraries.

Try below link, you will get lots of video on youtube.

Asp.net boilerplate

ABP Framework

Since Blazor Web Assembly still in preview, I start my personal website migration from asp.netcore 2.0 to blazor client side and Azure function for server side.

Here is my application structure

enter image description here

I hope it will help!

Share:
15,633
Dan
Author by

Dan

Updated on July 12, 2022

Comments

  • Dan
    Dan almost 2 years

    My company is moving from a legacy codebase to a more modern platform and we are moving to Blazor. We are currently just getting involved with ORM's and best practices and there seems to be a lot of conflicting ideas regarding project setup (at least from what I have gathered). My current structure is as follows:

    First is a class library called DAL - This is our "data layer". We are using Dapper and it is relatively straightforward. An example class would look like the following:

    public class Person
    {
          public string Id {get; set;}
          public string FirstName {get; set;}
          public string LastName {get; set;}
    
          public Person() {}
          public Person(DbContext context) {}
    
          public void GetPerson(int id) {}
          public void DeletePerson(int id) {}
    
    
          etc....
    }
    

    The second project is a server Blazor Project which references the project DAL. The project is divided like such:

    1. Models - These are models SPECIFIC to the current project being worked on. For example, one model might be a combination of several tables (Models from the DAL class) or just fields used for a form on a web page.

    An example might be like such:

    public class EmployeeModel
    {
        public int Id {get; set;}
        public int Department{get; set;}
        public DateTime HireDate {get; set;}
        public decimal Salary {get; set;}
        public Person {get; set;}
    }
    
    1. Pages - Razor pages/components with a page reference.
    2. Shared - Razor components - things used on multiple pages. An example would be a modal.
    3. Services - This is I suppose the business layer. As of right now, there is one service per model/class in the folder "Models" but there are also some for the shared components. An example for the EmployeeModel from the Models folder, might be as such:
    public class EmployeeService
    {
        private DbContext _dbContext = dbContext;
        public EmployeeService(DbContext dbContext)
        {
            _dbContext = dbContext;
        }
    
        public Task<EmployeeModel> Get(int id)
        {
            var personRepository = new Person(_dbContext);
            var person = personRepository.Get(id);
            Id = id;
            if (id > 10)
                Department = "Accounting"
            etc...
        }
    
        public Task<int>CalculateBonus(DateTime hireDate, string department, decimal salary)
        {
             //logic here...
        }
    }
    

    The services and dbcontext are all generated via dependency injection via startup.cs. The page class would load the data with something along these lines:

    
    @code{
    
        [Parameter]
        int EmployeeId;
    
        public Employee employee;
        public decimal bonus;
    
        protected override OnAfterRenderAsync(bool firstRender)
        {
            if (!firstRender)
                return;
    
            employee = EmployeeService.Get(EmployeeId);
        }
    
        public void GetBonus()
        {
            if (employee != null)
                bonus = EmployeeService.CalculateBonus(employee.HireDate, employee.Department, employee.Salary) 
        }
    }
    

    This seems to be going okay so far but there are A LOT of different interpretations out there. For instance, I liked the idea of using a MVVM pattern. An example I was originally following was at the following: https://itnext.io/a-simple-mvvm-implementation-in-client-side-blazor-8c875c365435

    However, I didn't see the purpose of separating out Model/ViewModel to how they were in that example, as they seemed to be doing the same thing but just at different areas within the application. I also couldn't find any other examples of this implementation online so I thought I was heading down the wrong path and initially scrapped that but am still early enough in the process to give that method a shot as well. For example, the EmployeeService class would look like such in this method:

    public class EmployeeService
    {
        private EmployeeModel _employeeModel;
        public EmployeeService(EmployeeModel employeeModel)
        {
            _employeeModel = employeeModel;
        }
    
        private EmployeeModel currentEmployee;
        public EmployeeModel CurrentEmployee
        {
            get { return currentEmployee}
        }
        {
            set {currentEmployee = value; }
        }
    
        public Task<EmployeeModel> Get(int id)
        {
             currentEmployee = EmployeeModel.Get(id);
        }
    
        public Task<int>CalculateBonus()
        {
             //logic implemented here with properties instead of parameters... 
        }
    }
    

    Then on the page it would be like the following:

    
    @code{
    
        [Parameter]
        int EmployeeId;
        public decimal bonus;
    
        protected override OnAfterRenderAsync(bool firstRender)
        {
            if (!firstRender)
                return;
    
            EmployeeService.Get(EmployeeId); //reference Employee on page with EmployeeService.CurrentEmployee
        }
    
        public void GetBonus()
        {
            bonus = EmployeeService.CalculateBonus();
        }
    }
    

    Seeing as how I was working with legacy code for so long and no one senior to tell me otherwise, I just want to know that I am doing it right. This is especially true since this is supposed to be the heart of our business moving forward and I don't want to wind up with spaghetti code or doing a complete refactor down the line.

    I guess my questions are as follows:

    1. How is my current implementation of a DAL? Is it okay to have the actual properties in line with the CRUD operations? As in having a constructor with the DBContext and one without? I have seen some projects have a separate library just for the class without the CRUD operations and I didn't see the value in that. The logic behind it being this way is most of our applications are just CRUD operations so I'd like to be able to just reuse that project in every application going forward. From looking online this implementation is a hybrid of a DAL/BLL

      1. Does my current implementation of Blazor "work"? Or are there any other better design practices I can follow? I like MVVM, but I really just don't see the value in any implementations I've seen so far. What is the point of having a page call a function on a ViewModel, that just calls a function in another class with the same name/parameters? Wouldn't it make sense to cut out the middle man so to speak?

      2. Are there any sample enterprise projects that I could follow to get a better idea of what to do here? As I've stated, there is no one senior at my company to go to regarding any of this. I am just trying to make it as adaptable to change/professional as possible.

    Thanks in advance for the help!

  • Dan
    Dan over 4 years
    Thank you very much! This is definitely helpful... I suppose what hurts me here (as with most tutorials) is that our current code base is such a mess... the database is informix and a lot of the programs being written are in C or VB6 and even if we wanted to do EF (we've tried), the schema is so bad that it doesn't even work (tables with no primary keys, no foreign keys, bad column names/types, etc.). It's not ideal hence why I'm using DAPPER and was hoping what I had would be okay in the long run.
  • weblar83
    weblar83 about 4 years
    @Dan I know you posted this last year but I find myself in exactly the same situation as yourself. I've read countless articles, forum posts and blog posts but I can't seem to find a common backend "template" which these articles agree upon. Some articles show 3 projects: a client, a shared project and a server project whereby the client uses JSON requests via Controllers to get at the data. I've seen examples using MVVM but I'm not sure I like this approach. I'd be interested to hear whether you managed to resolve this or find a more complete "enterprise" example as a starting point.
  • Dan
    Dan about 4 years
    @weblar83 check out the answer I posted beneath here that's what I wound up doing. The Data folder was the objects with business logic and the Services was the data layer. I had a folder for authorization, pages, and components as well. It worked out very nicely