您的位置:首页 > Web前端 > Vue.js

vue前端开发那些事——后端接口.net core web api

2018-12-09 21:23 1181 查看

  红花还得绿叶陪衬。vue前端开发离不开数据,这数据正来源于请求web api。为什么采用.net core web api呢?因为考虑到跨平台部署的问题。即使眼下部署到window平台,那以后也可以部署到Linux下。

  .net core web api与mvc的web api类似。我把遇到的问题归纳下:

1、部署问题

都说.net core web api,后面我简称api。它有两种部署方式,一个是在iis上部署,另外一个是自托管,类似控制台,通过dotnet  run 命令启动的。

 1.1 自托管部署

dotnet myapp.dll

网上说,通过hosting.json

{
"server.urls": "http://localhost:60000;http://localhost:60001"
}

这种方式有个问题,在配置了urls,并没有走配置。

public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();

var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();

host.Run();
}

不过人家是说在Linux环境下的部署,我在window下测试是不行的,不知道是哪的问题,后面可以再研究。

1.2、iis上部署

必须首先安装AspNetCoreModule,搜索这个模块,它的描述如下:

The ASP.NET Core Module allows ASP.NET Core apps to run in an IIS worker process (in-process) or behind IIS in a reverse proxy configuration (out-of-process). IIS provides advanced web app security and manageability features. 

这句话大意:api有两种运行模式,一种是运行在iis工作进程中(In-process hosting model),另外一种是通过反向代理配置,运行在外(Out-of-process hosting model)。具体,可参考官方文档

 

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace ElectronInfoApi.Business {
public class GlobalExceptionMiddleware {
private  readonly RequestDelegate next;
public GlobalExceptionMiddleware(RequestDelegate next) {
this.next = next;
}

public async Task Invoke(HttpContext context) {
try {
await next(context);
}
catch (Exception ex) {
await HandleExceptionAsync(context, ex);
}
}

private  async Task HandleExceptionAsync(HttpContext context, Exception exception) {
if (exception == null)return;
await WriteExceptionAsync(context, exception).ConfigureAwait(false);
}

private  async Task WriteExceptionAsync(HttpContext context, Exception exception) {
//记录日志
this.Log().Error($"系统发生了异常:{exception.Message}, {exception.StackTrace}");
//返回友好的提示
var response = context.Response;

//状态码
if (exception is UnauthorizedAccessException)
response.StatusCode = (int)HttpStatusCode.Unauthorized;
else if (exception is Exception)
response.StatusCode = (int)HttpStatusCode.BadRequest;

response.ContentType = context.Request.Headers["Accept"];

response.ContentType = "application/json";
await response.WriteAsync(JsonConvert.SerializeObject(new {state=400,message="出现未知异常"})).ConfigureAwait(false);
}

}

public static class VisitLogMiddlewareExtensions
{
public static IApplicationBuilder UseGlobalException(this IApplicationBuilder builder)
{
return builder.UseMiddleware<GlobalExceptionMiddleware>();
}
}
}
View Code 在startup>Configure中添加

app.UseGlobalException();

官网有文档,是这么定义中间件的:

Middleware is software that's assembled into an app pipeline to handle requests and responses

3、安全验证

接口验证,是为了安全性考虑,采用Jwt(Json web token)。

第一步,添加包引用:

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.1.2" />

第二步,配置:

"Issuer": "ElectronInfo",
"Audience": "ElectronInfo",
"SecretKey": "ElectronInfo is a web of shanxi dianzi qingbao weiyuanhui"

第三步,在Startup>ConfigureServices中添加授权服务:

var jwtSettings = new JwtSettings(){
Issuer=AppSetting.GetConfig("Issuer"),
Audience=AppSetting.GetConfig("Audience"),
SecretKey=AppSetting.GetConfig("SecretKey"),
};

services.AddAuthentication(options =>  {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>  {
o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters {
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey)),
       ValidateIssuerSigningKey = true,
ValidateIssuer = true,
       ValidateLifetime = true,
       ClockSkew = TimeSpan.Zero
};
});

第四步:在Startup>Configure中添加

app.UseAuthentication();

第五步:给整个Controller或者需要接口验证的action中添加

[Authorize]

附:AppSetting类,读取appsettings.json,如下:

using System.IO;
using Microsoft.Extensions.Configuration;

namespace ElectronInfoApi.Business {
public class AppSetting {
private static readonly object objLock = new object();
private static AppSetting instance = null;

private IConfigurationRoot Config {get; }

private AppSetting() {
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional:false, reloadOnChange:true);
Config = builder.Build();
}

public static AppSetting GetInstance() {
if (instance == null) {
lock (objLock) {
if (instance == null) {
instance = new AppSetting();
}
}
}

return instance;
}

public static string GetConfig(string name) {
return GetInstance().Config.GetSection(name).Value;
}
}}
View Code

4、日志log4

    .net core中本来就支持console输出日志。不过今天我要说的是log4,在传统的.net中普遍使用。

    第一步,添加包引用:

<PackageReference Include="log4net" Version="2.0.8" />

  第二步,添加配置文件log4net.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- This section contains the log4net configuration settings -->
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout" value="%date [%thread] %-5level %logger - %message%newline" />
</appender>

<!--<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="log-file.log" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender> -->

<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logfile/" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<staticLogFileName value="false" />
<datePattern value="yyyyMMdd'.log'" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>

<!-- Setup the root category, add the appenders and set the default level -->
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
<!--<appender-ref ref="FileAppender" />-->
<appender-ref ref="RollingLogFileAppender" />
</root>

</log4net>
</configuration>
View Code

第三步,包装以及扩展log4,为了更方便使用:

首先定义一个接口IMLog:

using System;

namespace ElectronInfoApi.Business {
public interface IMLog {
// Methods
void Debug(string message);
void Error(string message, Exception exception);
void Error(string message);
void Fatal(string message);
void Info(string message);
void Warn(string message);
}
public interface IMLog < T >  {

}
View Code

再定义包装器Log4NetWapper:

using System;
using log4net;
using log4net.Core;

namespace ElectronInfoApi.Business {
public class Log4NetWapper:IMLog, IMLog < Log4NetWapper >  {

private ILog  _logger;

public Log4NetWapper(string loggerName) {
this._logger = LogManager.GetLogger(Startup.repository.Name, loggerName);
}

public void Debug(string message) {
_logger.Debug(message);
}

public void Error(string message, Exception exception) {
_logger.Error(message, exception);
}

public void Error(string message) {
_logger.Error(message);
}

public void Fatal(string message) {
_logger.Fatal(message);
}

public void Info(string message) {
_logger.Info(message);
}

public void Warn(string message) {
_logger.Warn(message);
}
}

}
View Code

最后定义扩展方法 LogExtensions:

using System.Collections.Concurrent;

namespace ElectronInfoApi.Business {
public static class LogExtensions {
// Fields
private static readonly ConcurrentDictionary < string, IMLog > _dictionary = new ConcurrentDictionary < string, IMLog > ();

// Methods
public static IMLog Log(this string objectName) {
if ( ! _dictionary.ContainsKey(objectName)) {
IMLog log = new Log4NetWapper(objectName);
_dictionary.TryAdd(objectName, log);
}
return _dictionary[objectName];
}

public static IMLog Log < T > (this T type) {
return typeof(T).FullName.Log();
}
}}
View Code

第四步,在Startup中使用:

public static ILoggerRepository repository {get; set; }

public Startup(IConfiguration configuration) {
repository = LogManager.CreateRepository("NETCoreRepository");
XmlConfigurator.Configure(repository, new FileInfo("log4net.config"));
Configuration = configuration;
}
public IConfiguration Configuration {get; }

5、.对net core中startup理解,见官方文档

好了,关于.net core api也是第一次正式使用,就总结到这里。

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: