我一哥们从公司跳槽,推荐我去华为面试。大家也知道,华为不需要.net程序员,去了还要转java,你要是放到3年前的那次面试,你放我英语四级一马,我还真就去了,现在虽然你不刻意要求英语,可以放宽限制,我也是有心无力,真的是没精力去转什么java。和有些公司就是没有缘分,没办法的事。
今天我们来看一下ASP.NET Core的增删改查Demo。首先我们来看一下项目结构。
大家发现了吧,图标变了,在创建ASP.NET Core项目前,确保你已经安装了VS2015。
OK,接下来我们大概看一下项目文件,先看Project.json
我们看到了,是一些引用的dll还有一些发布运行时的配置,这个有点类似于node.js中的package.json包管理文件。
我们再来看appsettings.json
就是一些键值对的配置,ok,当然我们也可以在web.config中配置。再看一下bundleconfig.json。
之前我们用的是bundle.cs,而现在也换成了json文件配置。配置了输入原js,css以及输出js,css的压缩文件。OK,我们看这些文件也只是为了看区别。接下来我们把框架搭起来,很熟悉,Repository被Service调用,Service被controller调用。数据访问层是EF,采用database first模式。
首先我们要创建好数据库,然后我们按照微软官方网站的示例,根据database生成model。
https://docs.efproject.net/en/latest/platforms/aspnetcore/existing-db.html
ok,model生成好之后,我们看一下。
生成的整整齐齐,和之前的T4模板一样。注意在AttendanceManageContext文件中有数据库连接字符串,以及表结构定义,包括表关联关系。AttendanceManageContext继承DbContext,这一点没有变。
public partial class AttendanceManageContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder
{
#warning To protect potentially sensitive information in your connection
optionsBuilder.UseSqlServer(@"Server=IGFMVQVM354PFSB\BRUCE;Database=Atte..."
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Auth>(entity =>
{
entity.HasKey(e => e.TransactionNumber)
.HasName("PK__Auth__E733A2BE21B6055D");
entity.Property(e => e.AuthName)
.IsRequired()
.HasMaxLength(50);
entity.Property(e => e.InDate).HasColumnType("datetime");
});
modelBuilder.Entity<Department>(entity =>
{
entity.HasKey(e => e.TransactionNumber)
.HasName("PK__Departme__E733A2BE25869641");
entity.Property(e => e.DepartmentName)
.IsRequired()
.HasMaxLength(500);
entity.Property(e => e.InDate).HasColumnType("datetime");
});
}
..........
}OK,我们再看一下Repository。
public interface IRepository<TEntity> where TEntity : class, new()
{
void Update(TEntity entity);
void Remove(TEntity entity);
void Create(TEntity entity);
}定义一个接口,然后用BaseRepository继承并实现
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class, new()
{
protected DbContext _context;
DbSet<TEntity> _dbSet;
public BaseRepository(DbContext context)
{
this._context = context;
this._dbSet = context.Set<TEntity>();
}
public void Update(TEntity tEntity)
{
this._dbSet.Attach(tEntity);
this._context.Entry(tEntity).State = EntityState.Modified;
}
public void Remove(TEntity tEntity)
{
if (_context.Entry(tEntity).State == EntityState.Detached)
{
_dbSet.Attach(tEntity);
}
_dbSet.Remove(tEntity);
}
public void Create(TEntity tEntity)
{
_dbSet.Add(tEntity);
}OK,接下来我们看一下IUserRepository,定义两个接口方法。
public interface IUserRepository : IRepository<Users>
{
IPagedList<Users> GetUserList(string userName, int pageIndex, int pageSize);
Task<Users> GetUserById(int userId);
}再看一下实现,注意这里GetUserById是个异步方法。
public class UserRepository : BaseRepository<Users>, IUserRepository
{
public UserRepository(DbContext dbContext)
: base(dbContext)
{
}
public IPagedList<Users> GetUserList(string userName, int pageIndex, int pageSize)
{
IQueryable<Users> users = this._context.Set<Users>();
if (!string.IsNullOrEmpty(userName))
{
users = users.Where(t => t.RealName.Contains(userName));
}
return new PagedList<Users>(users, pageIndex, pageSize);
}
public async Task<Users> GetUserById(int userId)
{
return await this._context.Set<Users>().FirstOrDefaultAsync(u=>u.UserId==userId);
}
}接下来我们来看下Service层,先看IUserService。
public interface IService<TEntity>
where TEntity : class, new()
{
void Create(TEntity entity);
void Remove(TEntity entity);
void Update(TEntity entity);
}再看实现,全程泛型,注意这里的工作单元。
public class BaseService<TEntity> : IService<TEntity>
where TEntity : class, new()
{
protected AttendanceManageContext dbContext;
IRepository<TEntity> repository;
protected IUnitOfWork unitOfWork;
public BaseService()
{
this.dbContext = new AttendanceManageContext();
this.unitOfWork = new UnitOfWork(dbContext);
this.repository = new BaseRepository<TEntity>(dbContext);
}
public void Create(TEntity entity)
{
this.repository.Create(entity);
this.unitOfWork.Commit();
}
public void Remove(TEntity entity)
{
this.repository.Remove(entity);
this.unitOfWork.Commit();
}
public void Update(TEntity entity)
{
this.repository.Update(entity);
this.unitOfWork.Commit();
}
}ok,接下来我们看一下IUserService的定义。
public interface IUserService : IService<Users>
{
IPagedList<Users> GetUserList(string userName, int pageIndex, int pageSize);
Task<Users> GetUserById(int userId);
}再看实现,很简单的模式,不解释。
public class UserService : BaseService<Users>, IUserService
{
IUserRepository userRepository;
public UserService()
{
this.userRepository = new UserRepository(this.dbContext);
}
public IPagedList<Users> GetUserList(string userName, int pageIndex, int pageSize)
{
return this.userRepository.GetUserList(userName, pageIndex, pageSize);
}
public async Task<Users> GetUserById(int userId)
{
return await this.userRepository.GetUserById(userId);
}
}现在万事具备,只欠东风。看一下表现层控制器。
using Microsoft.AspNetCore.Mvc;
using CURDDemo.Models;
using CURDDemo.Service.UserMng;
using CURDDemo.Model.ViewModel;
using CURDDemo.Resources;
namespace CURDDemo.Controllers
{
public class HomeController : Controller
{
IUserService _userService;
public HomeController(IUserService userService)
{
this._userService = userService;
}
public IActionResult Index(int pageIndex = 0, int pageSize = 5, string userName = "")
{
var userList = this._userService.GetUserList(userName, pageIndex, pageSize);
UsersModel userModel = new UsersModel
{
UserList = userList,
UserName = userName
};
return View(userModel);
}
[HttpGet]
public IActionResult Edit(int userId)
{
ViewBag.Title = UserResource.title_edit;
var user = this._userService.GetUserById(userId).Result;
return View("~/Views/Home/CreateOrUpdate.cshtml", user);
}
public IActionResult EditUser(Users user)
{
var userDB = this._userService.GetUserById(user.UserId).Result;
if (userDB != null)
{
userDB.RealName = user.RealName;
userDB.TelNumber = user.TelNumber;
}
this._userService.Update(userDB);
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Create()
{
return View("~/Views/Home/CreateOrUpdate.cshtml");
}
[HttpPost]
public IActionResult CreateUser(Users user)
{
ViewBag.Title = UserResource.title_create;
this._userService.Create(user);
return RedirectToAction("Index");
}
[HttpDelete]
public IActionResult Remove(int userId)
{
var user = this._userService.GetUserById(userId).Result;
if (user != null)
{
this._userService.Remove(user);
}
return RedirectToAction("Index");
}
}
}注意这里的构造函数依赖注入,这里我们注入工具为Autofac。首先我们要在项目中引用Autofac,
选择管理NuGet程序包,找到Autofac.Extensions.DependencyInjection。
安装好之后,我们在项目中可以看到引用的dll。
ok,完了之后我们还要配置,打开Startup.cs。首先增加一个属性
public IContainer ApplicationContainer { get; private set; }然后我们将方法ConfigureServices改造如下
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var connection = @"Server=IGFMVQVM354PFSB\BRUCE;Database=AttendanceManage;Trusted_Connection=True;";
services.AddDbContext<AttendanceManageContext>(options => options.UseSqlServer(connection));
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
var builder = new ContainerBuilder();
builder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();
builder.Populate(services);
this.ApplicationContainer = builder.Build();
return new AutofacServiceProvider(this.ApplicationContainer);
}OK,我们在这里已经注册了类型UserService和接口的映射关系,并且指明生命周期。好的,我们回到controller,其实controller的实现代码以及路由和之前的也没啥区别。
我们直接看UI,还是熟悉的razor。
首先我们看一下_Layout.cshtml。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - CURDDemo</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
<script src="~/lib/jquery/dist/jquery.js"></script>
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
@Html.ApplicationInsightsJavaScript(TelemetryConfiguration)
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">CURDDemo</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© 2016 - CURDDemo</p>
</footer>
</div>
<environment names="Development">
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("scripts", required: false)
</body>
</html>和之前的差不多,只不过上面分了开发环境还是生产环境的一些js的引用。ok,我们再看Index.cshtml。
@model CURDDemo.Model.ViewModel.UsersModel
<div class="margin-t10">
<h4><label>用户信息列表</label></h4>
</div>
<div id="userlist" class="margin-t10">
@{await Html.RenderPartialAsync("~/Views/Partial/Users.cshtml", Model);}
</div>
<div class="row">
<div class="col-md-12">
@Html.ActionLink("新增", "Create", new { }, new { @class = "btn btn-info tab-btn" })
</div>
</div>一个用户信息列表界面,里面又引用了部分页users.cshtml。
@model CURDDemo.Model.ViewModel.UsersModel
<table class="table table-bordered table-hover table-striped">
<tr>
<th>
姓名
</th>
<th>
电话号码
</th>
<th>
操作
</th>
</tr>
@foreach (var user in Model.UserList)
{
<tr>
<td>
@user.RealName
</td>
<td>
@user.TelNumber
</td>
<td>
@Html.ActionLink("编辑","Edit",new { userId = user.UserId }, new { @class="btn btn-primary"})
@Html.ActionLink("删除", "Remove", new { userId = user.UserId }, new { @class = "btn btn-danger" })
</td>
</tr>
}
</table>
<div class="well well-sm">
共有 <span style="color: blue" id="ft">@Model.UserList.TotalCount</span>条记录 当前是第 <span style="color: blue">@(Model.UserList.PageIndex + 1)</span>
页 共<span style="color: blue">@Model.UserList.TotalPages</span>页
@if (Model.UserList.HasPreviousPage)
{
@Html.ActionLink("首页", "Index/0/" + Model.UserList.PageSize,
new { userName = Model.UserName },
new
{
data_ajax = "true",
data_ajax_method = "GET",
data_ajax_mode = "replace",
data_ajax_update = "#userlist",
style = "margin-left:5px;color:blue"
})
@Html.ActionLink("上一页", "Index/" + (Model.UserList.PageIndex - 1 + "/" + Model.UserList.PageSize),
new { userName = Model.UserName },
new
{
data_ajax = "true",
data_ajax_method = "GET",
data_ajax_mode = "replace",
data_ajax_update = "#userlist",
style = "margin-left:5px;color:blue"
})
}
else
{
<text>首页 </text>
<text>上一页 </text>
}
@if (Model.UserList.HasNextPage)
{
@Html.ActionLink("下一页", "Index/" + (Model.UserList.PageIndex + 1) + "/" + Model.UserList.PageSize,
new { userName = Model.UserName },
new
{
data_ajax = "true",
data_ajax_method = "GET",
data_ajax_mode = "replace",
data_ajax_update = "#userlist",
style = "margin-left:5px;color:blue"
})
@Html.ActionLink("末页", "Index/" + (Model.UserList.TotalPages - 1) + "/" + Model.UserList.PageSize,
new { userName = Model.UserName },
new
{
data_ajax = "true",
data_ajax_method = "GET",
data_ajax_mode = "replace",
data_ajax_update = "#userlist",
style = "margin-left:5px;color:blue"
})
}
else
{
<text>下一页 </text>
<text>末页 </text>
}
</div>不过是一个列表带分页。注意这里没有什么所谓的Ajax.ActionLink,只有Html.ActionLink,通过匿名对象设置ajax的一些配置。之前的AjaxOptions的一些属性的设置都成了这些data_属性。这里我们设置请求方式为Get,页面内容响应模式为替换,替换的div的id为userlist。Ok,讲到这里也就差不多了,之前我也讲过类似的代码,运行走起。
分页也是没什么问题的。
ok,我们点击编辑。
新增界面,看一下。
点击保存,有验证,为空通不过,看一下修改和创建界面。
@model CURDDemo.Models.Users
<link rel="stylesheet" href="~/js/validator/css/bootstrapValidator.css" />
<script type="text/javascript" src="~/js/validator/js/bootstrapValidator.js"></script>
<div class="margin-t10">
<h4><label>@ViewBag.Title</label></h4>
</div>
<form action="@Url.Action("EditUser")" method="put">
@Html.HiddenFor(m=>m.UserId)
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label>姓名:</label>
@Html.TextBoxFor(m => m.RealName, new { @class = "form-control", maxlength = 30 })
</div>
<div class="form-group">
<label>电话号码:</label>
@Html.TextBoxFor(m => m.TelNumber, new { @class = "form-control", maxlength = 30 })
</div>
<div class="margin-top-10">
<input type="submit" class="btn btn-primary tab-btn" value="保存" />
<input type="reset" class="btn btn-primary tab-btn" />
</div>
<div class="margin-top-10">
<span style="color: red">
@ViewBag.ErrorMsg
</span>
</div>
</div>
</div>
</form>
<script type="text/javascript">
$(function () {
$(‘form‘).bootstrapValidator({
message: ‘This value is not valid‘,
feedbackIcons: {
valid: ‘glyphicon glyphicon-ok‘,
invalid: ‘glyphicon glyphicon-remove‘,
validating: ‘glyphicon glyphicon-refresh‘
},
fields: {
RealName: {
validators: {
notEmpty: {
message: ‘姓名不能为空‘
}
}
},
TelNumber: {
validators: {
notEmpty: {
message: ‘电话号码不能为空‘
}
}
}
}
});
});
</script>在这里我们使用了bootstrapValidator,语法很简单,就不解释了。不早了,今天就到这里。如果想要源码,请加群205217091
本文出自 “技术创造价值” 博客,请务必保留此出处http://leelei.blog.51cto.com/856755/1865210
原文地址:http://leelei.blog.51cto.com/856755/1865210