不知不觉在科技二路已经上班长达十年了,从佳贝大厦到零一广场,太多的年头,一个年轻小伙熬成了大叔。年轻的时候什么都想折腾,什么都能折腾。现在感觉力不从心,电脑拿出来不知道自己要学什么,迷失了方向。
说这些废话也没啥用,不如写点博客来的实在,看一下我们的项目结构
关于这个EFCore链接SqlServer数据库在这我就不多说了,没啥说的。看项目结构就看得出来是工作单元模式,这个玩意我也不想多解释什么,截个图你细品。
依赖注入我们依然使用autofac,实体映射还是autoMapper,没啥说的。.net core 3.1版本,autofac需要这两步,在programe.cs中增加代码UseServiceProviderFactory
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
然后再Startup.cs中增加方法ConfigureContainer,再该方法中去设置注入的一些class。
public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType<MembershipManageContext>().As<DbContext>().InstancePerLifetimeScope(); builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope(); builder.RegisterType<CustomerRepository>().As<ICustomerRepository>().InstancePerLifetimeScope(); builder.RegisterType<CustomerService>().As<ICustomerService>().InstancePerLifetimeScope(); }
ok,接下来我们看一下server端的api接口,创建customer
[ApiController] [Route("[controller]")] public class CustomerController : ControllerBase { private readonly ICustomerService customerService; private readonly IMapper mapper; public CustomerController( ICustomerService customerService, IMapper mapper) { this.customerService = customerService; this.mapper = mapper; } [HttpGet("get")] public IEnumerable<Customer> GetCustomerList() { return customerService.GetCustomerList(); } [HttpPost("create")] public void CreateCustomer(CustomerRequest customerRequest) { var customer = mapper.Map<Customer>(customerRequest); customerService.CreateCustomer(customer); } }
这里我们注入了IMapper用于将前端提交的DTO实体转化为EFCore需要存储的DB对象。那这个mapper怎么知道映射规则呢?当然我们必须得自己写映射的规则了,安装AutoMapper.Extensions.Microsoft.DependencyInjection,然后我们新建一个class专门用于customer实体的映射规则。
public class CustomerProfile : Profile { public CustomerProfile() { CreateMap<CustomerRequest, Customer>(); } }
这里的基类Profile是AutoMapper命名空间下的,只要是继承了该类,在依赖注入解析的时候,就会从所有继承了Profile类的设置中查找对应的设置,对实体进行转化。
好的,说了这么久,api是实现好了。我们看一下页面的实现,直接上代码
@page "/customer/create" @using WebAssemblyDemo.Shared.Customer @using WebAssemblyDemo.Server.Models @inject HttpClient Http <EditForm Model="@customer" OnValidSubmit="onValidSubmit" OnInvalidSubmit="onInvalidSubmit"> <div id="customer" class="margin-t10"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title"> <label>新增会员</label> </h3> </div> <div class="panel-content"> <div class="row"> <div class="col-md-12"> <div class="form-group" style="height:35px"> <label class="col-md-2"><span class="text-danger">*</span>用户名:</label> <div class="col-md-10"> <input id="userNo" name="userNo" type="text" @bind-value="customer.UserNo" class="form-control" maxlength="11" autocomplete="off" placeholder="输入手机号" /> <ValidationMessage For="()=>customer.UserNo"></ValidationMessage> </div> </div> <div class="form-group" style="height:35px"> <label class="col-md-2"><span class="text-danger">*</span>密码:</label> <div class="col-md-10"> <input id="userPwd" name="passWord" type="password" @bind-value="customer.Password" class="form-control" maxlength="10" /> <ValidationMessage For="()=>customer.Password"></ValidationMessage> </div> </div> <div class="form-group" style="height:35px"> <label class="col-md-2"><span class="text-danger">*</span>确认密码:</label> <div class="col-md-10"> <input id="userRePwd" name="userRePwd" type="password" @bind-value="customer.RePassword" class="form-control" maxlength="10" /> <ValidationMessage For="()=>customer.RePassword"></ValidationMessage> </div> </div> <div class="form-group" style="height:35px"> <label class="col-md-2"><span class="text-danger">*</span>姓名:</label> <div class="col-md-10"> <input id="name" name="name" type="text" class="form-control" @bind-value="customer.Name" maxlength="10" autocomplete="off" /> <ValidationMessage For="()=>customer.Name"></ValidationMessage> </div> </div> <div class="form-group" style="height:35px"> <label class="col-md-2"><span class="text-danger">*</span>性别:</label> <div class="col-md-10"> <select id="userSex" name="sex" class="form-control" @bind="customer.Sex"> <option value="">---请选择---</option> <option value="1">男</option> <option value="0">女</option> </select> <ValidationMessage For="()=>customer.Sex"></ValidationMessage> </div> </div> <div class="form-group" style="height:35px"> <label class="col-md-2">推荐人:</label> <div class="col-md-10"> <InputSelect @bind-Value="customer.ParentID" class="form-control"> @foreach (var customer in customerList) { <option value="@customer.Id">@customer.Name</option> } </InputSelect> </div> </div> <div class="form-group" style="height:35px"> <label class="col-md-2"></label> <div class="col-md-10"> <button type="submit" class="btn btn-primary">保存</button> </div> </div> </div> </div> </div> <DataAnnotationsValidator /> @*<ValidationSummary />*@ </div> </div> </EditForm> @code { private List<Customer> customerList = new List<Customer>(); private CustomerRequest customer = new CustomerRequest(); private EditContext editContext; protected override async Task OnInitializedAsync() { editContext = new EditContext(customer); customerList = await Http.GetFromJsonAsync<List<Customer>>("customer/get"); } private void onValidSubmit() { this.Http.PostAsJsonAsync<CustomerRequest>("customer/create", customer); } private void onInvalidSubmit() { } }
在这里,所有表单都进行了双向绑定,使用@bind-value或者@bind。大家注意到必填项下面都有一个ValidationMessage元素,这个是框架提供的组件,用来显示验证信息。在这里只需要设置For="()=>customer.Sex",Lambda表达式中只需要写你需要验证的字段即可。另外大家注意到这里框架提供的InputSelect,除了这个组件外,还有如下的一些内置组件可供使用
大家自己研究即可。在组件的初始化完成以后,我们会实例化EditContext并传入该表单绑定的数据模型对象。然后因为我们的下拉列表需要数据源,所以发请求去请求api拿到customerList,注意在顶部,我们直接注入http实例,即可使用。这个页面我们定义的路由地址是customer/create,所以我们在浏览器输入这个地址,看一下页面运行的效果图
推荐人这一栏下拉列表已经加载上了从api请求的数据,验证消息也显示出来了,我们看一下验证怎么实现的,其实验证就是在绑定实体上打上验证标签,如下
public class CustomerRequest { public int ID { get; set; } [Required(ErrorMessage = "用户名不能为空!")] public string UserNo { get; set; } [Required(ErrorMessage = "性别不能为空!")] public Nullable<int> Sex { get; set; } public Nullable<System.DateTime> InDate { get; set; } public string InUser { get; set; } [Required(ErrorMessage = "姓名不能为空!")] public string Name { get; set; } public int ParentID { get; set; } [Required(ErrorMessage = "密码不能为空!")] [StringLength(10, ErrorMessage = "密码长度必须介于6到10位!", MinimumLength = 6)] [RegularExpression("^[0-9a-zA-Z_]{1,}$", ErrorMessage = "密码必须由字母数组和下划线组成!")] public string Password { get; set; } [Required(ErrorMessage = "确认密码不能为空!")] [Compare("Password", ErrorMessage = "确认密码和密码不一致!")] public string RePassword { get; set; } public bool Status { get; set; } }
ok,其实这个实现和asp.net mvc的实现有些类似。好的,最后我们再看一下提交,只有验证通过了我们才能请求api去创建customer,所以我们在onValidSubmit方法中去请求api创建customer。看下面的方法,很直接发送json格式数据去请求api
this.Http.PostAsJsonAsync<CustomerRequest>("customer/create", customer);
提交,直接进入断点,如下,没有问题
当然我们只验证客户端表单是远远不够的,我们还要在API端进行验证。我们在Swagger看一下
在这里userno为空,sex=-1,我们看一下验证效果
看到没,请求还未到达action,已经被半路拦截了。ok,今天就到这里,拜拜
上一篇 WebAssembly&.NET
匿名游客
匿名游客