Asp.net MVC Api项目搭建

整个解决方案按照分层思想来划分不同功能模块,以提供User服务的Api为需求,各个层次的具体实现如下所示:

1、新建数据库User表

数据库使用SQLExpress版本,表的定义如下所示:

sql 复制代码
CREATE TABLE [dbo].[User] (
    [Id]               INT           IDENTITY (1, 1) NOT NULL,
    [Name]             NVARCHAR (50) NOT NULL,
    [Password]         NVARCHAR (50) NOT NULL,
    [Age]              INT           NOT NULL,
    [Birthdate]        DATE          NOT NULL,
    [CreateTime]       DATETIME      DEFAULT (getdate()) NOT NULL,
    [CreateUserId]     NVARCHAR (50) NOT NULL,
    [CreateUserName]   NVARCHAR (50) NOT NULL,
    [ModifiedTime]     DATETIME      NULL,
    [ModifiedUserId]   NVARCHAR (50) NULL,
    [ModifiedUserName] NVARCHAR (50) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

2、实体层

新建类库类型的项目,.net framework框架版本4.5,User实体类如下:

cs 复制代码
public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Password { get; set; }
        public int Age { get; set; }
        public DateTime Birthdate { get; set; }
        public DateTime CreateTime { get; set; }
        public string CreateUserId { get; set; }
        public string CreateUserName { get; set; }
        public DateTime? ModifiedTime { get; set; }
        public string ModifiedUserId { get; set; }
        public string ModifiedUserName { get; set; }
    }

3、数据库层

该层提供数据库接口操作,采用EntitFramework4.4.0.0作为ORM实体映射框架,

  • 定义数据库操作接口IRepository
cs 复制代码
public interface IRepository<TEntity> : IDisposable where TEntity : class
    {
        IEnumerable<TEntity> Get();
        IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter);
        IEnumerable<TEntity> Get<TOderKey>(Expression<Func<TEntity, bool>> filter, int pageIndex, int pageSize, Expression<Func<TEntity, TOderKey>> sortKeySelector, bool isAsc = true);

        int Count(Expression<Func<TEntity, bool>> predicate);
        void Update(TEntity instance);
        void Add(TEntity instance);
        void Delete(TEntity instance);
    }
  • 定义数据库上下文类BceDbContext
cs 复制代码
public class BceDbContext:DbContext
    {
        public BceDbContext():base("DaLeiDB")
        {
            Database.SetInitializer<AceDbContext>(null);
        }
        public DbSet<User> Users { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>().ToTable("User");
            base.OnModelCreating(modelBuilder);
        }
    }
  • 定义数据库通用操作实现类BceRepository
cs 复制代码
public class BceRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        public BceDbContext DbContext { get; private set; }
        public DbSet<TEntity> DbSet { get; private set; }
        public BceRepository(BceDbContext context)
        {
            Guard.ArgumentNotNull(context, "context");
            this.DbContext = context;
            this.DbSet = this.DbContext.Set<TEntity>();
        }

        public IEnumerable<TEntity> Get()
        {
            return this.DbSet.AsQueryable();
        }
        public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter)
        {
            return this.DbSet.Where(filter).AsQueryable();
        }
        public IEnumerable<TEntity> Get<TKey>(Expression<Func<TEntity, bool>> filter, int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> sortKeySelector, bool isAsc = true)
        {
            Guard.ArgumentNotNull(filter, "predicate");
            Guard.ArgumentNotNull(sortKeySelector, "sortKeySelector");
            if (isAsc)
            {
                return this.DbSet
                    .Where(filter)
                    .OrderBy(sortKeySelector)
                    .Skip(pageSize * (pageIndex - 1))
                    .Take(pageSize).AsQueryable();
            }
            else
            {
                return this.DbSet
                    .Where(filter)
                    .OrderByDescending(sortKeySelector)
                    .Skip(pageSize * (pageIndex - 1))
                    .Take(pageSize).AsQueryable();
            }
        }

        public int Count(Expression<Func<TEntity, bool>> predicate)
        {
            return this.DbSet.Where(predicate).Count();
        }

        public void Add(TEntity instance)
        {
            Guard.ArgumentNotNull(instance, "instance");
            this.DbSet.Attach(instance);
            this.DbContext.Entry(instance).State = EntityState.Added;
            this.DbContext.SaveChanges();
        }
        public void Update(TEntity instance)
        {
            Guard.ArgumentNotNull(instance, "instance");
            this.DbSet.Attach(instance);
            this.DbContext.Entry(instance).State = EntityState.Modified;
            this.DbContext.SaveChanges();
        }
        public void Delete(TEntity instance)
        {
            Guard.ArgumentNotNull(instance, "instance");
            this.DbSet.Attach(instance);
            this.DbContext.Entry(instance).State = EntityState.Deleted;
            this.DbContext.SaveChanges();
        }

        public void Dispose()
        {
            this.DbContext.Dispose();
        }
    }
  • 定义用户表数据库操作额外的接口IUserRepository
cs 复制代码
namespace DaLei.Repository
{
    public interface IUserRepository
    {
        User FindByName(string name);
        List<User> FindByAge(int start, int end);
    }
}
  • 定义用户表数据库操作额外的实现类UserRepository

    cs 复制代码
    namespace DaLei.Repository
    {
        public class UserRepository : BceRepository<User>, IUserRepository
        {
            public UserRepository(BceDbContext bceDbContext):base(bceDbContext)
            {
    
            }
    
            public List<User> FindByAge(int start, int end)
            {
                var rst = this.DbSet.AsQueryable().Where(u=>u.Age>=start && u.Age<=end).ToList();
                return rst;
            }
    
            public User FindByName(string name)
            {
                var rst = this.DbSet.AsQueryable().Where(u => u.Name == name).FirstOrDefault();
                return rst;
            }
        }
    }

4、服务接口层

定义了对外提供用户服务的接口契约,具体如下:

cs 复制代码
namespace DaLei.IService
{
    public interface IUserService
    {
        User FindByName(string name);
        List<User> FindByAge(int start, int end);
        List<User> GetList();
    }
}

5、服务具体实现层

服务基类实现:

cs 复制代码
using System;
using System.Collections.Generic;

namespace DaLei.Service
{
    public abstract class ServiceBase : IDisposable
    {
        public IList<IDisposable> DisposableObjects { get; private set; }
        public ServiceBase()
        {
            this.DisposableObjects = new List<IDisposable>();
        }
        protected void AddDisposableObject(object obj)
        {
            IDisposable disposable = obj as IDisposable;
            if (null != disposable)
            {
                this.DisposableObjects.Add(disposable);
            }
        }

        public void Dispose()
        {
            foreach (IDisposable obj in this.DisposableObjects)
            {
                if (null != obj)
                {
                    obj.Dispose();
                }
            }
        }
    }
}

用户服务接口具体实现:

cs 复制代码
using DaLei.IService;
using DaLei.Model;
using DaLei.Repository;
using System.Collections.Generic;

namespace DaLei.Service
{
    public class UserService : ServiceBase,IUserService
    {
        private IUserRepository userRepository;
        public UserService(IUserRepository userRepository)
        {
            this.userRepository = userRepository;
            this.AddDisposableObject(userRepository);
        }
        public List<User> FindByAge(int start, int end)
        {
            return this.userRepository.FindByAge(start,end);
        }

        public User FindByName(string name)
        {
            return this.userRepository.FindByName(name);
        }

        public List<User> GetList()
        {
            return this.userRepository.FindByAge(0, 100);
        }
    }
}

6、应用层

新建Asp.net WebApi项目,引用服务接口项目、服务实现项目、实体类项目,unity相关程序集,EntityFramework程序集。

web.config配置连接字符串和unity相关内容:

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  https://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity>
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
    <containers>
      <container>
        <extension type="Interception" />
        <register type="DaLei.IService.IUserService, DaLei.IService" mapTo="DaLei.Service.UserService, DaLei.Service" />
        <register type="DaLei.Repository.IUserRepository, DaLei.Repository" mapTo="DaLei.Repository.UserRepository, DaLei.Repository">
          <interceptor type="InterfaceInterceptor" />
          <policyInjection />
        </register>
      </container>
    </containers>
  </unity>
  <connectionStrings>
    <add name="DaLeiDB" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=DaleiDB;User ID=sa;Password=anpiel0991;" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <appSettings>
    <add key="webpages:Version" value="3.0.0.0"/>
    <add key="webpages:Enabled" value="false"/>
    <add key="PreserveLoginUrl" value="true"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5"/>
    <httpRuntime targetFramework="4.5"/>
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers"/>
        <add namespace="System.Web.Mvc"/>
        <add namespace="System.Web.Mvc.Ajax"/>
        <add namespace="System.Web.Mvc.Html"/>
        <add namespace="System.Web.Routing"/>
        <add namespace="System.Web.WebPages"/>
      </namespaces>     
    </pages>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
      <remove name="OPTIONSVerbHandler"/>
      <remove name="TRACEVerbHandler"/>
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler"
        preCondition="integratedMode,runtimeVersionv4.0"/>
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed"/>
        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-5.2.7.0" newVersion="5.2.7.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>
</configuration>
  • Controller实例化由Unity负责处理,需要实现控制器工厂类
cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

namespace WebApi.Extensions
{
    public class UnityControllerFactory : DefaultControllerFactory
    {
        static object syncHelper = new object();
        static Dictionary<string, IUnityContainer> containers = new Dictionary<string, IUnityContainer>();
        public IUnityContainer UnityContainer { get; private set; }
        public UnityControllerFactory(string containerName = "")
        {
            if (containers.ContainsKey(containerName))
            {
                this.UnityContainer = containers[containerName];
                return;
            }
            lock (syncHelper)
            {
                if (containers.ContainsKey(containerName))
                {
                    this.UnityContainer = containers[containerName];
                    return;
                }
                IUnityContainer container = new UnityContainer();
                //配置UnityContainer
                UnityConfigurationSection configSection = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
                if (null == configSection && !string.IsNullOrEmpty(containerName))
                {
                    throw new ConfigurationErrorsException("The <unity> configuration section does not exist.");
                }
                if (null != configSection)
                {
                    if (string.IsNullOrEmpty(containerName))
                    {
                        configSection.Configure(container);
                    }
                    else
                    {
                        configSection.Configure(container, containerName);
                    }
                }
                containers.Add(containerName, container);
                this.UnityContainer = containers[containerName];
            }
        }
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (null == controllerType)
            {
                return null;
            }
            return (IController)this.UnityContainer.Resolve(controllerType);
        }
//public override void ReleaseController(IController controller)
//{
//    this.UnityContainer.Teardown(controller);
//}
    }
}
  • 设置MVC框架的控制器工厂为自定义类型
cs 复制代码
using webApi.Extensions;
using System;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

namespace WebApp
{
    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            // 在应用程序启动时运行的代码
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());
        }
    }
}
  • 新建Controller基类,所有的自定义Controller均继承此类
cs 复制代码
using WebApi.Extensions;
using System.Web.Mvc;
using System;
using System.Collections.Generic;

namespace WebApp.Controllers
{
    public class BaseController:Controller
    {
        public IList<IDisposable> DisposableObjects { get; private set; }
        public BaseController()
        {
            this.DisposableObjects = new List<IDisposable>();
        }
        protected void AddDisposableObject(object obj)
        {
            IDisposable disposable = obj as IDisposable;
            if (null != disposable)
            {
                this.DisposableObjects.Add(disposable);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                foreach (IDisposable obj in this.DisposableObjects)
                {
                    if (null != obj)
                    {
                        obj.Dispose();
                    }
                }
            }
            base.Dispose(disposing);
        }
    }
}
  • 新建测试Controller
cs 复制代码
using DaLei.IService;
using System.Web.Mvc;

namespace WebApp.Controllers
{
    public class TestController : BaseController
    {
        private IUserService userService;
        public TestController(IUserService userService)
        {
            this.userService = userService;
            this.AddDisposableObject(userService);
        }

        // GET: Test
        public ActionResult Index()
        {
            var users = this.userService.GetList();
            return View();
        }
    }
}

浏览器输入地址测试TestController!

相关推荐
William_cl2 天前
一、前置基础(MVC学习前提)_核心特性_【C# 泛型入门】为什么说 List<T>是程序员的 “万能收纳盒“?避坑指南在此
学习·c#·mvc
程序员小凯3 天前
Spring MVC 分布式事务与数据一致性教程
分布式·spring·mvc
艾菜籽3 天前
SpringMVC练习:加法计算器与登录
java·spring boot·spring·mvc
程序员小凯3 天前
Spring MVC 多租户架构与数据隔离教程
spring·架构·mvc
艾菜籽4 天前
Spring Web MVC入门补充1
java·后端·spring·mvc
艾菜籽4 天前
Spring MVC入门补充2
java·spring·mvc
风兮w4 天前
MVC、MVP和MVVM的区别
mvc
蓝天智能5 天前
QT MVC中Model的特点及使用注意事项
qt·mvc
低音钢琴5 天前
【SpringBoot从初学者到专家的成长15】MVC、Spring MVC与Spring Boot:理解其差异与联系
spring boot·spring·mvc
.NET修仙日记5 天前
2025年ASP.NETMVC面试题库全解析
面试·职场和发展·c#·asp.net·mvc·面试题·asp.net mvc