为何要写这篇文章?
最初是一个很常规的WebApiece项目基于 .net framework 4.7.2, 调试时部署在本地IIS
测试完成后需要部署到服务器上, 不想再配IIS(由于之前有多个.netcore项目都是托管在Windows服务中), 多以就找找了相关的资料,决定使用相似的方式来改造以下.
OwinSelfHost 资料
添加项目文件夹 Controllers
添加一个控制器, 代码如下
[RoutePrefix("api/consumer")]
public class ConsumerController : ApiControllerBase
{
private readonly ILog _log;
///
/// 实例化一个 对象
///
public ConsumerController(ILog log) // 使用autofac作为依赖注入容器,集成方式后面会有介绍
{
_log = log ?? throw new ArgumentNullException(nameof(log));
}
[HttpPost]
[Route("create")]
public async Task<IHttpActionResult> CreateConsumerAsync([FromBody] ConsumerInfoCreateDto consumer)
{
// 这里有用到 AutoMapper, 集成方式后面会有介绍
try
{
....
return Ok();
}
catch (Exception ex)
{
_log.Error("consumer-create", ex);
return BadRequest(ex.InnerException == null ? ex.Message : ex.InnerException.Message);
}
}
}
代码如下(示例):
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
Setup 中添加如下代码:
///
/// Autofac 配置
///
///
private static void ConfigureAutofac(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.ComponentRegistryBuilder.Registered += (sender, args) =>
{
args.ComponentRegistration.PipelineBuilding += (o, pipelineBuilder) =>
{
pipelineBuilder.Use(new Log4NetMiddleware());
};
};
builder.RegisterWebApiFilterProvider(config);
builder.RegisterWebApiModelBinderProvider();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
在 Configuration 方法中添加如下代码:
public void Configuration(IAppBuilder appBuilder)
{
......
ConfigureAutofac(config);
......
}
Log4net 集成
以中间件的方式将Log4net添加到autofac中
相关代码:
public class Log4NetMiddleware : IResolveMiddleware
{
///
///
///
///
///
public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next)
{
context.ChangeParameters(context.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, i) => p.ParameterType == typeof(ILog),
(p, i) => LogManager.GetLogger(p.Member.DeclaringType)
),
}));
// Continue the resolve.
next(context);
if (context.NewInstanceActivated)
{
var instanceType = context.Instance.GetType();
var properties = instanceType
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.PropertyType == typeof(ILog) && p.CanWrite && p.GetIndexParameters().Length == 0);
foreach (var propToSet in properties)
{
propToSet.SetValue(context.Instance, LogManager.GetLogger(instanceType), null);
}
}
}
///
///
///
public PipelinePhase Phase => PipelinePhase.ParameterSelection;
}
Log4net 配置文件
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
configSections>
<log4net>
.......
log4net>
configuration>
这里很重要 ! ! ! 在AssemblyInfo 中添加
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "config", Watch = true)]
Setup 中添加如下代码:
private static void ConfigureSwagger(HttpConfiguration config)
{
var thisAssembly = typeof(Startup).Assembly;
var parentPath = Path.GetDirectoryName(thisAssembly.Location);
config.EnableSwagger(action =>
{
action.SingleApiVersion("v1", "swagger doc");
action.IncludeXmlComments($@"{parentPath}\xxxxx.xml");
}).EnableSwaggerUi(action =>
{
action.DocumentTitle("title");
});
}
在 Configuration 方法中添加如下代码:
public void Configuration(IAppBuilder appBuilder)
{
......
ConfigureSwagger(config);
......
}
添加 AutoMapper 配置类, 代码如下:
public static class AutoMapperConfig
{
public static IMapper Mapper { get; private set; }
public static void Configure()
{
var config = new MapperConfiguration(cfg =>
{
#region consumer info
cfg.CreateMap<ConsumerInfoCreateDto, ConsumerInfo>();
cfg.CreateMap<ConsumerInfo, ConsumerInfoDto>();
#endregion
});
Mapper = config.CreateMapper();
}
}
在 Configuration 方法中添加如下代码:
public void Configuration(IAppBuilder appBuilder)
{
......
AutoMapperConfig.Configure();
......
}
在 Controller 中通过以下方式使用:
AutoMapperConfig.Mapper.Map<ConsumerInfo>(consumer)
代码如下:
static void Main(string[] args)
{
var baseUri = "http://localhost:xxxx";
WebApp.Start<Startup>(url: baseUri);
Console.ReadLine();//
}
到这里基本上已经可以了
创建Windows 服务 可借助 sc 相关的命令,
目前为止, 如果使用sc来创建服务,创建的服务是启动不了的.
添加一个继承自 ServiceBase 的类
代码如下:
public class WinService : ServiceBase
{
protected override void OnStart(string[] args)
{
var baseUri = "http://localhost:xxxx";
WebApp.Start<Startup>(url: baseUri);
}
}
改造 Program
static void Main(string[] args)
{
var ServiceCollections = new ServiceBase[]
{
new WinService()
};
ServiceBase.Run(ServiceCollections);
}
解决跨域
添加 Nuget Microsoft.AspNet.Cors
修改Configuration
public void Configuration(IAppBuilder appBuilder)
{
......
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));// 允许所有
......
}
好了,就到这吧 ༼ つ ◕_◕ ༽つ