asp.net mvc+web api+easyui

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了asp.net mvc+web api+easyui相关的知识,希望对你有一定的参考价值。

前奏:第一次写博客,记录一下学习和开发的过程。

现在写的是一个后台管理系统,有基本的权限功能,其他功能都可以扩展。用到的技术是 asp.net mvc5,web api 2,entityframework,autofac,easyui等。

先来上个解决方案的图: 技术分享

01-ZY.Web.MVC:是页面的展示,由于用了web api 所以在mvc里面没有做数据的操作。mvc里面主要有权限的判断,controller里面也没有太多的逻辑处理。

02-ZY.Web.Api:这里用到了web api。web api的好处是可以多平台调用,前后端可以分别开发,很好的分离了前后端的开发工作。

03-ZY.Identity:这里面主要是权限的判断,用到了asp.net identity。

04-ZY.Core:这个是项目的核心类库,包含了autofac,缓存,仓储接口,实体基类,扩展方法等,后续会详细的讲讲。

05-ZY.Repositories.EntityFramework:这个就是EntityFramework仓储的实现。

06-ZY.Model:这个就是实体类库。

在看一下运行的效果图片:

1:账号管理界面

技术分享

2:编辑管理员  角色是多角色。

技术分享

3:管理员选中角色,多角色选择,查找带回控件

技术分享

4.设置菜单权限界面

技术分享

5.角色管理  角色管理是在行内编辑

技术分享

6.设置角色权限

技术分享

7.菜单管理

技术分享

8.设置菜单需要的按钮权限

技术分享

再贴一些代码吧:

 

仓储接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

using ZY.Core.Entities;

namespace ZY.Core.Repositories
{
    /// <summary>
    /// 仓储接口
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public interface IRepository<TEntity, TKey> : IDependency where TEntity : IEntity<TKey>
    {
        IQueryable<TEntity> Entities { get; }

        #region 同步添加方法
        /// <summary>
        /// 添加实体对象
        /// </summary>
        /// <param name="entity"></param>
        void Insert(TEntity entity);
        /// <summary>
        /// 批量添加实体对象
        /// </summary>
        /// <param name="entitys"></param>
        void Insert(IEnumerable<TEntity> entitys);
        #endregion

        #region 同步删除方法
        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="entity"></param>
        void Remove(TEntity entity);
        /// <summary>
        /// 根据主键删除
        /// </summary>
        /// <param name="key"></param>
        void Remove(TKey key);
        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <param name="predicate"></param>
        void Remove(Expression<Func<TEntity, bool>> predicate);
        /// <summary>
        /// 批量删除对象
        /// </summary>
        /// <param name="entitys"></param>
        void Remove(IEnumerable<TEntity> entitys);
        /// <summary>
        /// 根据主键批量删除
        /// </summary>
        /// <param name="keys"></param>
        void Remove(IEnumerable<TKey> keys);
        #endregion

        #region 同步修改方法
        /// <summary>
        /// 修改对象实体
        /// </summary>
        /// <param name="entity"></param>
        void Update(TEntity entity);
        #endregion

        #region 同步判断方法
        /// <summary>
        /// 根据主键判断实体是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        bool Exists(TKey key);
        /// <summary>
        /// 根据添加判断是否存在
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        bool Exists(Expression<Func<TEntity, bool>> predicate);
        #endregion

        #region 同步查询单条
        /// <summary>
        /// 根据主键查询
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        TEntity GetByKey(TKey key);
        /// <summary>
        /// 根据条件获取单条记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        TEntity FirstOfDefault(Expression<Func<TEntity, bool>> predicate);
        #endregion

        #region 同步查询列表
        /// <summary>
        /// 根据条件获取数据列表
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate);

        #endregion

        #region 异步添加方法
        /// <summary>
        /// 添加实体对象
        /// </summary>
        /// <param name="entity"></param>
        Task<TEntity> InsertAsync(TEntity entity);
        /// <summary>
        /// 批量添加实体对象
        /// </summary>
        /// <param name="entitys"></param>
        Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> entitys);
        #endregion

        #region 异步修改方法
        /// <summary>
        /// 修改对象实体
        /// </summary>
        /// <param name="entity"></param>
        Task<TEntity> UpdateAsync(TEntity entity);
        #endregion

        #region 异步判断方法
        /// <summary>
        /// 根据主键判断实体是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Task<bool> ExistsAsync(TKey key);
        /// <summary>
        /// 根据添加判断是否存在
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate);
        #endregion

        #region 异步查询单条
        /// <summary>
        /// 根据主键查询
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Task<TEntity> GetByKeyAsync(TKey key);
        /// <summary>
        /// 根据条件获取单条记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        Task<TEntity> FirstOfDefaultAsync(Expression<Func<TEntity, bool>> predicate);
        #endregion

        #region 异步查询列表
        /// <summary>
        /// 查询全部数据
        /// </summary>
        /// <returns></returns>
        Task<List<TEntity>> GetAllAsync();
        /// <summary>
        /// 根据条件获取数据列表
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> predicate);
        
        #endregion

        #region 同步sql查询
        /// <summary>
        /// 根据sql查询
        /// </summary>
        /// <param name="query"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        IEnumerable<TEntity> SqlQuery(string sql, params object[] parameters);
        #endregion
    }
}

仓储的具体实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Data.Entity;

using ZY.Core.Repositories;
using ZY.Core.Entities;
using System.Linq.Expressions;

namespace ZY.Repositories.EntityFramework
{
    /// <summary>
    /// EntityFramework 仓储
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public class Repository<TEntity, TKey> : IRepository<TEntity, TKey>
        where TEntity : class, IEntity<TKey>
    {
        protected DbContext _dbContext;
        protected IDbSet<TEntity> _dbSet;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext"></param>
        public Repository(DbContext dbContext)
        {
            _dbContext = dbContext;
            _dbSet = dbContext.Set<TEntity>();
        }

        /// <summary>
        /// 全部实体对象
        /// </summary>
        public IQueryable<TEntity> Entities
        {
            get
            {
                return _dbSet.AsQueryable();
            }
        }

        #region 同步添加方法
        /// <summary>
        /// 添加实体对象
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Insert(TEntity entity)
        {
            _dbSet.Add(entity);
        }
        /// <summary>
        /// 批量添加实体对象
        /// </summary>
        /// <param name="entitys"></param>
        public virtual void Insert(IEnumerable<TEntity> entities)
        {
            _dbContext.Set<TEntity>().AddRange(entities);
        }
        #endregion

        #region 同步删除方法
        /// <summary>
        /// 删除对象实体
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Remove(TEntity entity)
        {
            _dbSet.Remove(entity);
        }
        /// <summary>
        /// 根据主键删除实体
        /// </summary>
        /// <param name="key"></param>
        public virtual void Remove(TKey key)
        {
            var entity = GetByKey(key);
            if (entity == null)
                return;
            Remove(entity);
        }
        /// <summary>
        /// 删除对象列表
        /// </summary>
        /// <param name="entities"></param>
        public virtual void Remove(IEnumerable<TEntity> entities)
        {
            if (entities == null)
                return;
            if (!entities.Any())
                return;
            _dbContext.Set<TEntity>().RemoveRange(entities);
        }
        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <param name="predicate"></param>
        public virtual void Remove(Expression<Func<TEntity, bool>> predicate)
        {
            var entities = _dbSet.Where(predicate);
            Remove(entities);
        }
        /// <summary>
        /// 根据主键列表删除
        /// </summary>
        /// <param name="keys"></param>
        public virtual void Remove(IEnumerable<TKey> keys)
        {
            if (keys == null)
                return;
            Remove(Query(t => keys.Contains(t.Id)));
        }
        #endregion

        #region 同步修改方法
        /// <summary>
        /// 修改对象实体
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Update(TEntity entity)
        {
            _dbContext.Entry(entity).State = EntityState.Modified;
        }
        #endregion

        #region 同步判断方法
        /// <summary>
        /// 判断主键是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual bool Exists(TKey key)
        {
            return GetByKey(key) == null ? false : true;
        }
        /// <summary>
        /// 根据条件判断对象是否存在
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual bool Exists(Expression<Func<TEntity, bool>> predicate)
        {
            return Query(predicate).Any();
        }
        #endregion

        #region 同步查询单条
        /// <summary>
        /// 根据主键获取对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual TEntity GetByKey(TKey key)
        {
            return _dbContext.Set<TEntity>().Find(key);
        }
        /// <summary>
        /// 获取单个实体
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual TEntity FirstOfDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return Query(predicate).FirstOrDefault();
        }
        #endregion

        #region 同步查询列表
        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate)
        {
            return _dbSet.Where(predicate);
        }

        #endregion

        #region 异步添加方法
        /// <summary>
        /// 添加实体对象
        /// </summary>
        /// <param name="entity"></param>
        public virtual Task<TEntity> InsertAsync(TEntity entity)
        {
            return Task.FromResult(_dbSet.Add(entity));
        }
        /// <summary>
        /// 批量添加实体对象
        /// </summary>
        /// <param name="entitys"></param>
        public virtual Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> entities)
        {
            return Task.FromResult(_dbContext.Set<TEntity>().AddRange(entities));
        }
        #endregion

        #region 同步修改方法
        /// <summary>
        /// 修改对象实体
        /// </summary>
        /// <param name="entity"></param>
        public virtual Task<TEntity> UpdateAsync(TEntity entity)
        {
            _dbContext.Entry(entity).State = EntityState.Modified;
            return Task.FromResult(entity);
        }
        #endregion

        #region 异步判断方法
        /// <summary>
        /// 判断主键是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<bool> ExistsAsync(TKey key)
        {
            return await GetByKeyAsync(key) == null ? false : true;
        }
        /// <summary>
        /// 根据条件判断对象是否存在
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual async Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await Query(predicate).AnyAsync();
        }
        #endregion

        #region 异步查询单条
        /// <summary>
        /// 根据主键获取对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> GetByKeyAsync(TKey key)
        {
            return await _dbContext.Set<TEntity>().FindAsync(key);
        }
        /// <summary>
        /// 获取单个实体
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> FirstOfDefaultAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await Query(predicate).FirstOrDefaultAsync();
        }
        #endregion

        #region 异步查询列表
        /// <summary>
        /// 查询全部数据
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> GetAllAsync()
        {
            return await _dbSet.ToListAsync();
        }
        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await _dbSet.Where(predicate).ToListAsync();
        }
        #endregion

        #region 同步sql方法
        /// <summary>
        /// 根据sql查询
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public IEnumerable<TEntity> SqlQuery(string sql, params object[] parameters)
        {
            return _dbContext.Database.SqlQuery<TEntity>(sql, parameters);
        }
        #endregion
    }
}

关于Repository的具体实现思路,博客园里面有很多文章了,这里就不详细说明了。

IUnitOfWork  考虑到可能会执行单独的存储过程,所以在UnitOfWork里面加了对存储过程的支持

using System;
using System.Data;
using System.Threading.Tasks;

namespace ZY.Core.Repositories
{
    /// <summary>
    /// 业务单元操作接口
    /// </summary>
    public interface IUnitOfWork: IDependency, IDisposable
    {
        /// <summary>
        /// 提交
        /// </summary>
        /// <returns></returns>
        void Commit();
        /// <summary>
        /// 异步提交
        /// </summary>
        /// <returns></returns>
        Task CommitAsync();
        /// <summary>
        /// 同步
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        int ExecuteSqlCommand(string sql, params object[] parameters);
        /// <summary>
        /// 异步执行SQL语句
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        Task<int> ExecuteSqlCommandAsync(string sql, params object[] parameters);
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="storedProcName">存储过程名称</param>
        /// <returns></returns>
        DataSet QueryProcedure(string storedProcName);
        /// <summary>
        /// 执行存储过程 带参数
        /// </summary>
        /// <param name="storedProcName">存储过程名称</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        DataSet QueryProcedure(string storedProcName, IDataParameter[] parameters);
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="storedProcName">存储过程名称</param>
        /// <param name="parameters">参数</param>
        /// <returns>存储过程返回值</returns>
        int RunProcedure(string storedProcName, IDataParameter[] parameters);
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="storedProcName">存储过程名称</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        int RunProcedure(string storedProcName);
    }
}

  

UnitOfWork的具体实现

using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Validation;
using System.Data.SqlClient;
using System.Text;
using System.Threading.Tasks;
using ZY.Core.Logging;
using ZY.Core.Repositories;

namespace ZY.Repositories.EntityFramework
{
    /// <summary>
    /// 工作单元
    /// </summary>
    public class UnitOfWork : IUnitOfWork
    {
        private DbContext _dbContext; //数据库上下文对象
        private readonly ILog log; //日志接口

        public UnitOfWork(DbContext dbContext)
        {
            _dbContext = dbContext;
            log = new Log();
        }

        /// <summary>
        /// 提交
        /// </summary>
        /// <returns></returns>
        public void Commit()
        {
            try
            {
                try
                {
                    _dbContext.SaveChanges();
                }
                catch (DbEntityValidationException exception)
                {
                    throw new DataException("保存数据时,数据验证引发异常--", exception);
                }
            }
            catch (DbUpdateException ex)
            {
                throw new DataException("保存数据更改时引发异常--", ex);
            }
        }
        /// <summary>
        /// 异步提交
        /// </summary>
        /// <returns></returns>
        public async Task CommitAsync()
        {
            try
            {
                try
                {
                    await _dbContext.SaveChangesAsync();
                }
                catch (DbEntityValidationException exception)
                {
                    throw new DataException("保存数据时,数据验证引发异常--", exception);
                }
            }
            catch (DbUpdateException ex)
            {
                throw new DataException("保存数据更改时引发异常--",ex);
            }
        }
        /// <summary>
        /// 异步
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public async Task<int> ExecuteSqlCommandAsync(string sql, params object[] parameters)
        {
            return await _dbContext.Database.ExecuteSqlCommandAsync(sql, parameters);
        }
        /// <summary>
        /// 同步
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public int ExecuteSqlCommand(string sql, params object[] parameters)
        {
            return _dbContext.Database.ExecuteSqlCommand(sql, parameters);
        }
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="storedProcName">存储过程名称</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public DataSet QueryProcedure(string storedProcName, IDataParameter[] parameters)
        {
            using (SqlConnection connection = new SqlConnection(_dbContext.Database.Connection.ConnectionString))
            {
                try
                {
                    DataSet dataSet = new DataSet();
                    connection.Open();
                    SqlDataAdapter sqlDA = new SqlDataAdapter();
                    sqlDA.SelectCommand = BuildQueryCommand(connection, storedProcName, parameters);
                    sqlDA.Fill(dataSet);
                    connection.Close();
                    return dataSet;
                }
                catch (Exception exception)
                {
                    string error = string.Format("执行存储过程 名称:{0} 参数 {1}", storedProcName, GetParamterValue(parameters));
                    log.Error(error, exception);
                    throw new Exception(error, exception);
                }
            }
        }
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="storedProcName">存储过程名称</param>
        /// <returns></returns>
        public DataSet QueryProcedure(string storedProcName)
        {
            using (SqlConnection connection = new SqlConnection(_dbContext.Database.Connection.ConnectionString))
            {
                try
                {
                    DataSet dataSet = new DataSet();
                    connection.Open();
                    SqlDataAdapter sqlDA = new SqlDataAdapter();
                    SqlCommand command = new SqlCommand(storedProcName, connection);
                    command.CommandType = CommandType.StoredProcedure;
                    sqlDA.SelectCommand = command;
                    sqlDA.Fill(dataSet);
                    connection.Close();
                    return dataSet;
                }
                catch (Exception exception)
                {
                    string error = string.Format("执行存储过程 名称:{0}", storedProcName);
                    log.Error(error, exception);
                    throw new Exception(error, exception);
                }
            }
        }
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="storedProcName">存储过程名称</param>
        /// <param name="parameters">参数</param>
        /// <returns>存储过程返回值</returns>
        public int RunProcedure(string storedProcName, IDataParameter[] parameters)
        {
            using (SqlConnection connection = new SqlConnection(_dbContext.Database.Connection.ConnectionString))
            {
                try
                {
                    connection.Open();
                    SqlCommand command = BuildQueryCommand(connection, storedProcName, parameters);
                    SqlParameter resultParam = new SqlParameter(); //构建存储过程返回值
                    resultParam.Direction = ParameterDirection.ReturnValue;
                    command.Parameters.Add(resultParam);
                    command.ExecuteNonQuery();
                    connection.Close();
                    return (int)resultParam.Value;
                }
                catch (Exception exception)
                {
                    string error = string.Format("执行存储过程 名称:{0} 参数 {1}", storedProcName, GetParamterValue(parameters));
                    log.Error(error, exception);
                    throw new Exception(error, exception);
                }
            }
        }
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="storedProcName">存储过程</param>
        /// <returns>返回值</returns>
        public int RunProcedure(string storedProcName)
        {
            using (SqlConnection connection = (SqlConnection)_dbContext.Database.Connection)
            {
                try
                {
                    connection.Open();
                    SqlCommand command = new SqlCommand(storedProcName, connection);
                    command.CommandType = CommandType.StoredProcedure;
                    SqlParameter resultParam = new SqlParameter(); //构建存储过程返回值
                    resultParam.Direction = ParameterDirection.ReturnValue;
                    command.Parameters.Add(resultParam);
                    command.ExecuteNonQuery();
                    connection.Close();
                    return (int)resultParam.Value;
                }
                catch (SqlException exception)
                {
                    string error = string.Format("执行存储过程 名称:{0}", storedProcName);
                    log.Error(error, exception);
                    throw new Exception(error, exception);
                }
            }
        }
        /// <summary>
        /// 构建 SqlCommand 对象(用来返回一个结果集,而不是一个整数值)
        /// </summary>
        /// <param name="connection">数据库连接</param>
        /// <param name="storedProcName">存储过程名</param>
        /// <param name="parameters">存储过程参数</param>
        /// <returns>SqlCommand</returns>
        private SqlCommand BuildQueryCommand(SqlConnection connection, string storedProcName, IDataParameter[] parameters)
        {
            SqlCommand command = new SqlCommand(storedProcName, connection);
            command.CommandType = CommandType.StoredProcedure;
            foreach (SqlParameter parameter in parameters)
            {
                if (parameter != null)
                {
                    // 检查未分配值的输出参数,将其分配以DBNull.Value.
                    if ((parameter.Direction == ParameterDirection.InputOutput || parameter.Direction == ParameterDirection.Input) &&
                        (parameter.Value == null))
                    {
                        parameter.Value = DBNull.Value;
                    }
                    command.Parameters.Add(parameter);
                }
            }
            return command;
        }
        /// <summary>
        /// 根据参数列表获取参数的名称和值,用于记录日志
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private string GetParamterValue(IDataParameter[] parameters)
        {
            StringBuilder paramStr = new StringBuilder();
            foreach (SqlParameter param in parameters)
            {
                paramStr.AppendFormat("{0} :{1}", param.ParameterName, param.Value);
            }
            return paramStr.ToString();
        }
        //处理回收机制
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        //处理回收机制
        private void Dispose(bool isdispose)
        {
            if (isdispose)
            {
                if (_dbContext != null)
                {
                    _dbContext.Dispose();
                    _dbContext = null;
                }
            }
        }
    }
}

  

 

 这篇文章就暂时到这里,下一篇会介绍ZY.Repositories.EntityFramework类库的实现。

以上是关于asp.net mvc+web api+easyui的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 4 Web API

AngularJS + ASP.NET Web API + ASP.NET MVC 身份验证

如何从 ASP.NET 核心 mvc 向 asp.net 核心中的 Web API 发出 PUT 请求?

ASP.NEt MVC 使用 Web API 返回 Razor 视图

Web APi Vs MVC 和在 ASP.net 核心 Web APi 中提供静态文件

初试ASP.NET Web API/MVC API(附Demo)