BodeAbp服务端只提供api,绝大部分api通过abp的动态WebApi机制提供,原理可以参考这篇文章:http://www.cnblogs.com/1zhk/p/5418694.html
与业务相关的api写在模块内部,这样服务端几乎都不需要有Controller了,目前整个项目只有“登录”和“文件上传”有Controller代码,最大化的减少业务模块与系统的耦合,也更方便业务模块的加载/卸载。
服务端目录结构:
BodeAbp.Frame:abp框架
BodeAbp.Modules:业务模块
BodeAbp.Plugins:插件
BodeAbp.Samples:示例
业务模块目录结构:
BodeAbp.Product:功能模块程序集
Localization:本地化资源文件夹
Providers:模块权限、菜单、设置项文件夹
Attributes:子功能文件夹(这里是商品属性)
Domain:领域层,存放聚合根、领域服务、值对象等。
Dtos:存放数据传输对象
ModelConfigs:存放Model配置类
SeedActions:存放种子数据(创建数据库或迁移数据库时添加到即数据库的数据)
...AppServices:应用程序服务,业务实现,是向外提供webapi的基础
Module中代码:
using System.Reflection; using Abp.EntityFramework.Default; using Abp.Localization.Dictionaries; using Abp.Localization.Dictionaries.Xml; using Abp.Modules; using BodeAbp.Product.Providers; namespace BodeAbp.Product { /// <summary> /// 产品模块 /// </summary> public class BodeAbpProductModule : AbpModule { /// <summary> /// 版本号 /// </summary> public const string CurrentVersion = "0.1.0"; /// <summary> /// 初始化前执行 /// </summary> public override void PreInitialize() { Configuration.Localization.Sources.Add( new DictionaryBasedLocalizationSource( BodeAbpProductConsts.LocalizationSourceName, new XmlEmbeddedFileLocalizationDictionaryProvider( Assembly.GetExecutingAssembly(), "BodeAbp.Product.Localization.Source" ) ) ); Configuration.Settings.Providers.Add<BodeAbpProductSettingProvider>(); Configuration.Navigation.Providers.Add<BodeAbpProductNavigationProvider>(); Configuration.Authorization.Providers.Add<BodeAbpProductAuthorizationProvider>(); DefaultDbContextInitializer.Instance.MapperAssemblies.Add(Assembly.GetExecutingAssembly()); } /// <summary> /// 初始化执行 /// </summary> public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } /// <summary> /// 初始化后执行 /// </summary> public override void PostInitialize() { base.PostInitialize(); } } }
关于abp中的模块机制,可以参考文章:http://www.cnblogs.com/farb/p/ABPModuleSystem.html
DefaultDbContextInitializer类是BodeAbp默认的数据库初始化类,可以仿造其实现将不同模块中的实体注册到不同的DbContext来达到分库的目的。DefaultDbContext默认读取webconfig中Default的连接字符串。
IApplicationService中代码:
using Abp.Application.Services; using System.ComponentModel; using Abp.Application.Services.Dto; using BodeAbp.Product.Attributes.Dtos; using System.Collections.Generic; using System.Threading.Tasks; namespace BodeAbp.Product.Attributes { /// <summary> /// 属性 服务 /// </summary> [Description("属性接口")] public interface IAttributesAppService : IApplicationService { #region 属性模版 /// <summary> /// 获取 属性模版分页 /// </summary> /// <param name="input"></param> /// <returns></returns> Task<PagedResultOutput<GetAttributeListOutput>> GetAttributePagedList(QueryListPagedRequestInput input); /// <summary> /// 获取 属性模版详情 /// </summary> /// <param name="id">id</param> /// <returns></returns> Task<GetAttributeOutput> GetAttribute(int id); /// <summary> /// 添加 属性模版 /// </summary> /// <param name="input"></param> /// <returns></returns> Task CreateAttribute(CreateAttributeInput input); /// <summary> /// 更新 属性模版 /// </summary> /// <param name="input"></param> /// <returns></returns> Task UpdateAttribute(UpdateAttributeInput input); /// <summary> /// 删除 属性模版 /// </summary> /// <param name="input"></param> /// <returns></returns> Task DeleteAttribute(List<IdInput> input); #endregion #region 属性值 /// <summary> /// 获取 属性值分页 /// </summary> /// <param name="input"></param> /// <returns></returns> Task<PagedResultOutput<GetAttributeOptionListOutput>> GetAttributeOptionPagedList(QueryListPagedRequestInput input); /// <summary> /// 获取 属性值详情 /// </summary> /// <param name="id">id</param> /// <returns></returns> Task<GetAttributeOptionOutput> GetAttributeOption(int id); /// <summary> /// 添加 属性值 /// </summary> /// <param name="input"></param> /// <returns></returns> Task CreateAttributeOption(CreateAttributeOptionInput input); /// <summary> /// 更新 属性值 /// </summary> /// <param name="input"></param> /// <returns></returns> Task UpdateAttributeOption(UpdateAttributeOptionInput input); /// <summary> /// 删除 属性值 /// </summary> /// <param name="input"></param> /// <returns></returns> Task DeleteAttributeOption(List<IdInput> input); #endregion #region 分类 /// <summary> /// 获取 分类分页 /// </summary> /// <param name="input"></param> /// <returns></returns> Task<PagedResultOutput<GetProductClassifyListOutput>> GetClassifyPagedList(QueryListPagedRequestInput input); /// <summary> /// 获取 分类详情 /// </summary> /// <param name="id">id</param> /// <returns></returns> Task<GetProductClassifyOutput> GetClassify(int id); /// <summary> /// 添加 分类 /// </summary> /// <param name="input"></param> /// <returns></returns> Task CreateClassify(CreateProductClassifyInput input); /// <summary> /// 更新 分类 /// </summary> /// <param name="input"></param> /// <returns></returns> Task UpdateClassify(UpdateProductClassifyInput input); /// <summary> /// 删除 分类 /// </summary> /// <param name="classifyId">分类Id</param> /// <returns></returns> Task DeleteClassify(int classifyId); #endregion } }
加载模块:
在WebApi项目的Module类中加载模块,代码如下:
using System.Reflection; using System.Web.Http; using Abp.Application.Services; using Abp.Configuration.Startup; using Abp.Modules; using Abp.WebApi; using Abp.WebApi.Controllers.Dynamic.Builders; using Swashbuckle.Application; using System.Linq; using System.Web.Http.Cors; using BodeAbp.Zero; using System; using WebDemo.WebApi.Swagger; using BodeAbp.Activity; using BodeAbp.Product; namespace WebDemo.WebApi { [DependsOn( typeof(AbpWebApiModule) , typeof(WebDemoCoreModule) , typeof(BodeAbpZeroModule) , typeof(BodeAbpActivityModule) , typeof(BodeAbpProductModule))] public class WebDemoWebApiModule : AbpModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); DynamicApiControllerBuilder .ForAll<IApplicationService>(typeof(WebDemoCoreModule).Assembly, "app") .Build(); DynamicApiControllerBuilder .ForAll<IApplicationService>(typeof(BodeAbpZeroModule).Assembly, "zero") .Build(); DynamicApiControllerBuilder .ForAll<IApplicationService>(typeof(BodeAbpActivityModule).Assembly, "activity") .Build(); DynamicApiControllerBuilder .ForAll<IApplicationService>(typeof(BodeAbpProductModule).Assembly, "product") .Build(); Configuration.Modules.AbpWebApi().HttpConfiguration.Filters.Add(new HostAuthenticationFilter("Bearer")); var cors = new EnableCorsAttribute("*", "*", "*"); GlobalConfiguration.Configuration.EnableCors(cors); ConfigureSwaggerUi(); } private void ConfigureSwaggerUi() { Configuration.Modules.AbpWebApi().HttpConfiguration .EnableSwagger(c => { c.SingleApiVersion("v1", "WebDemo.WebApi"); //c.OperationFilter<AuthorizationOperationFilter>(); c.DocumentFilter<ApplicationDocumentFilter>(); c.IncludeXmlComments(GetXmlCommentsPath(typeof(WebDemoCoreModule))); c.IncludeXmlComments(GetXmlCommentsPath(typeof(BodeAbpZeroModule))); c.IncludeXmlComments(GetXmlCommentsPath(typeof(BodeAbpActivityModule))); c.IncludeXmlComments(GetXmlCommentsPath(typeof(BodeAbpProductModule))); c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); }) .EnableSwaggerUi(c => { c.CustomAsset("index", typeof(WebDemoWebApiModule).Assembly, "WebDemo.WebApi.Swagger.index.html"); c.InjectStylesheet(typeof(WebDemoWebApiModule).Assembly, "WebDemo.WebApi.Swagger.theme-flattop.css"); c.InjectJavaScript(typeof(WebDemoWebApiModule).Assembly, "WebDemo.WebApi.Swagger.translator.js"); }); } private static string GetXmlCommentsPath(Type moduleType) { return string.Format(@"{0}\bin\{1}.XML", AppDomain.CurrentDomain.BaseDirectory, moduleType.Assembly.GetName().Name); } } }
浏览Api:
确保webconfig中数据库连接正确,直接运行项目,浏览器访问:http://localhost:61759/swagger/ui/index#/,效果图如下:
BodeAbp采用了swagger展示api,关于swagger的配置参考WebApi项目的Module类中的ConfigureSwaggerUi方法。