首页 > 代码库 > ASP.NET Core 实战(一)CURD

ASP.NET Core 实战(一)CURD

我一哥们从公司跳槽,推荐我去华为面试。大家也知道,华为不需要.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="http://www.mamicode.com/~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="http://www.mamicode.com/~/css/site.css" />
        <script src="http://www.mamicode.com/~/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="http://www.mamicode.com/~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="http://www.mamicode.com/absolute" />
        <link rel="stylesheet" href="http://www.mamicode.com/~/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>&copy; 2016 - CURDDemo</p>
        </footer>
    </div>

    <environment names="Development">
      
        <script src="http://www.mamicode.com/~/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="http://www.mamicode.com/~/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="http://www.mamicode.com/~/lib/bootstrap/dist/js/bootstrap.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
        </script>
        <script src="http://www.mamicode.com/~/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>页&nbsp;&nbsp;&nbsp;&nbsp;
    @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>首页&nbsp;</text>
    <text>上一页&nbsp;</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>下一页&nbsp;</text>
    <text>末页&nbsp;</text>
    }
</div>

不过是一个列表带分页。注意这里没有什么所谓的Ajax.ActionLink,只有Html.ActionLink,通过匿名对象设置ajax的一些配置。之前的AjaxOptions的一些属性的设置都成了这些data_属性。这里我们设置请求方式为Get,页面内容响应模式为替换,替换的div的id为userlist。Ok,讲到这里也就差不多了,之前我也讲过类似的代码,运行走起。

技术分享

分页也是没什么问题的。

技术分享

ok,我们点击编辑。

技术分享

新增界面,看一下。

技术分享

点击保存,有验证,为空通不过,看一下修改和创建界面。

@model CURDDemo.Models.Users
<link rel="stylesheet" href="http://www.mamicode.com/~/js/validator/css/bootstrapValidator.css" />
<script type="text/javascript" src="http://www.mamicode.com/~/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="http://www.mamicode.com/保存" />
                <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

ASP.NET Core 实战(一)CURD