locked
Server Side Blazor w Dapper - add a service RRS feed

  • Question

  • User379720387 posted

    This solution has two projects: one is the normal SSB structure and the other is a DataAccessLibrary to support integration with Dapper.

    I am attempting to implement Grid.Blazor as per these instructions, and the first step is "Create a service with a method to get all items for the grid".

    At the moment I have no understanding of what a service is, and if I do not already have a service, or if that is what I need for how things are implemented with Dapper. Those are my questions basically.

    Here is how I have things in the DataAccessLibrary:

    PeopleData.cs and I also have IPeopleData

    using DataAccessLibrary.Models;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DataAccessLibrary
    {
        public class PeopleData : IPeopleData
        {
            private readonly ISqlDataAccess _db;
    
            public PeopleData(ISqlDataAccess db)
            {
                _db = db;
            }
    
            public Task<List<PersonModel>> GetPeople()
            {
                string sql = "select uFName, uLName, Email, uMobile, uFromTo from dbo.UserProfile";
    
                return _db.LoadData<PersonModel, dynamic>(sql, new { });
            }
    
            public Task InsertPerson(PersonModel person)
            {
                string sql = @"insert into dbo.UserProfile (uFName, uLName, Email, uMobile, uFromTo)
                               values (@uFName, @uLName, @Email, @uMobile, @uFromTo);";
    
                return _db.SaveData(sql, person);
            }
        }
    }

    In the SSB project I have DisplayPersonModel:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace BlazorDemoUI.Models
    {
        public class DisplayPersonModel
        {
            [Required]
            [StringLength(10, ErrorMessage = "First Name is too long.")]
            [MinLength(2, ErrorMessage = "First Name is too short.")]
            public string uFName { get; set; }
    
            [Required]
            [StringLength(15, ErrorMessage = "Last Name is too long.")]
            [MinLength(2, ErrorMessage = "Last Name is too short.")]
            public string uLName { get; set; }
    
            [Required]
            [EmailAddress]
            public string Email { get; set; }
            
            [Required]
            [Phone]
            //[MaxLength(10, ErrorMessage = "not a valid mobile no.")]
            public string uMobile { get; set; }
    
        }
    }

    And lastly I have People.razor

    @page "/Data/People"
    
    @using DataAccessLibrary
    @using DataAccessLibrary.Models
    @using BlazorDemoUI.Models
    
    @inject IPeopleData _db
    
    <h1>Users</h1>
    
    <h4>Insert New Person</h4>
    <EditForm Model="@newPerson" OnValidSubmit="@InsertPerson">
        <DataAnnotationsValidator />
        <ValidationSummary />
    
        <InputText id="firstName" @bind-Value="newPerson.uFName" />
        <InputText id="lastName" @bind-Value="newPerson.uLName" />
        <InputText id="email" @bind-Value="newPerson.Email" />
        <InputText id="uMobile" @bind-Value="newPerson.uMobile" />
    
        <button type="submit" class="btn btn-primary">Add User</button>
    </EditForm>
    
    <h4>Current Users</h4>
    @if (people is null)
    {
        <p><em>Loading...</em></p>
    }
    else
    {
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>First Name</th>
                    <th>Last Name</th>
                    <th>Email</th>
                    <th>Mobile</th>
                    <td>uFromTo</td>
                </tr>
            </thead>
            <tbody>
                @foreach (var person in people)
                {
                    <tr>
                        <td>@person.uFName</td>
                        <td>@person.uLName</td>
                        <td>@person.Email</td>
                        <td>@person.uMobile</td>
                        <td>@person.uFromTo</td>
                    </tr>
                }
            </tbody>
        </table>
    }
    
    @code {
        private List<PersonModel> people;
        private DisplayPersonModel newPerson = new DisplayPersonModel();
    
        protected override async Task OnInitializedAsync()
        {
            people = await _db.GetPeople();
        }
    
        private async Task InsertPerson()
        {
            PersonModel p = new PersonModel
            {
                uFName = newPerson.uFName,
                uLName = newPerson.uLName,
                Email = newPerson.Email,
                uMobile =newPerson.uMobile,
                uFromTo ="+1" + newPerson.uMobile
            };
    
            await _db.InsertPerson(p);
    
            people.Add(p);
    
            newPerson = new DisplayPersonModel();
        }
    }
    

    My questions are:

    What a service is?

    Is there already a service?

    Do I need a service for how things are implemented with Dapper?

    Friday, November 27, 2020 8:45 PM

Answers

  • User-821857111 posted

    Here's a "service": 

    namespace MyApp.Services
    {
        public class PeopleService : IPeopleService
        {
            private readonly ISqlDataAccess _db;
    
            public PeopleService(ISqlDataAccess db)
            {
                _db = db;
            }
    
            public Task<List<PersonModel>> GetPeople()
            {
                string sql = "select uFName, uLName, Email, uMobile, uFromTo from dbo.UserProfile";
    
                return _db.LoadData<PersonModel, dynamic>(sql, new { });
            }
    
            public Task InsertPerson(PersonModel person)
            {
                string sql = @"insert into dbo.UserProfile (uFName, uLName, Email, uMobile, uFromTo)
                               values (@uFName, @uLName, @Email, @uMobile, @uFromTo);";
    
                return _db.SaveData(sql, person);
            }
        }
    }

    That's how I do things. I see Dapper, EF Core as the data access layer. This kind of "Service" in .NET Core are basically what were known as Business Logic classes in old skool. You register your service in the DI container and inject it into your component and call its methods.

    More generally, services are any class that you want to use within the application. Some are registered for you, such as an HttpClient for making calls to Web APIS, and a NavigationManager for managing programmatic navigation within the application. Most of them will be ones that you write to manage data and other business processes.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, November 27, 2020 10:09 PM
  • User-821857111 posted

    No. it's not a problem. You just need to add a reference  from within the Blazor project to the class library.

    I've added a bit to my previous answer too.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, November 28, 2020 6:37 AM

All replies

  • User-821857111 posted

    Here's a "service": 

    namespace MyApp.Services
    {
        public class PeopleService : IPeopleService
        {
            private readonly ISqlDataAccess _db;
    
            public PeopleService(ISqlDataAccess db)
            {
                _db = db;
            }
    
            public Task<List<PersonModel>> GetPeople()
            {
                string sql = "select uFName, uLName, Email, uMobile, uFromTo from dbo.UserProfile";
    
                return _db.LoadData<PersonModel, dynamic>(sql, new { });
            }
    
            public Task InsertPerson(PersonModel person)
            {
                string sql = @"insert into dbo.UserProfile (uFName, uLName, Email, uMobile, uFromTo)
                               values (@uFName, @uLName, @Email, @uMobile, @uFromTo);";
    
                return _db.SaveData(sql, person);
            }
        }
    }

    That's how I do things. I see Dapper, EF Core as the data access layer. This kind of "Service" in .NET Core are basically what were known as Business Logic classes in old skool. You register your service in the DI container and inject it into your component and call its methods.

    More generally, services are any class that you want to use within the application. Some are registered for you, such as an HttpClient for making calls to Web APIS, and a NavigationManager for managing programmatic navigation within the application. Most of them will be ones that you write to manage data and other business processes.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, November 27, 2020 10:09 PM
  • User379720387 posted

    Ok..... but my "service" lives in the Class Library, not in the Blazor project.

    Is that a problem?

    Saturday, November 28, 2020 3:57 AM
  • User-821857111 posted

    No. it's not a problem. You just need to add a reference  from within the Blazor project to the class library.

    I've added a bit to my previous answer too.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, November 28, 2020 6:37 AM
  • User379720387 posted

    I understand now why WeatherForecast and WeatherForecastService are part of the SSB project template. That was just hard coded data and there was no need for separation.

    Ok, thanks!

    Saturday, November 28, 2020 1:09 PM
  • User-821857111 posted

    I'd create a separate class library for "services" in a WebAssembly Blazor app, but not necessarily if I was building a server-side app, any more than I might if I was building a Razor Pages app. The difference between calling a database and having the data hardcoded in the service isn't really a factor. 

    You have two types of code separation - one is the physical separation of code into separate projects (dlls), which is done mainly for practical purposes to do with deployment, versioning, team working etc. The other is the logical separation of concerns, which is designed to enable loose coupling of dependencies. The main weapon in that fight is interfaces and dependency injection. The physical location of the service being injected is irrelevant.

    Saturday, November 28, 2020 8:38 PM