Micro 开发
创建 Asp.Net Core Web应用

创建控制器文件夹(Controllers),Program.cs 配置控制器路由
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
创建MVC区域文件夹(Areas),Program.cs 配置区域路由
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");

安装包
Ocelot.Provider.Consul
IdentityServer4.AccessTokenValidation
1.配置微服务
1)appsettings.json
"Consul": {
"ServiceName": "cms",
"IP": "127.0.0.1",
"Weight": "1",
"Port": "5017"
}
2)启动服务 ConsulBuilderExtensions.cs
using Consul;
namespace Micro.Cms
{
public static class ConsulBuilderExtensions
{
public static void ConsulExtend(this IConfiguration configuration, string serviceName)
{
ConsulClient client = new(m =>
{
//对应服务器的地址:consul的端口
m.Address = new Uri("http://127.0.0.1:8500/");
m.Datacenter = "cms";
});
//启动的时候在consul中注册实例服务
//在consul中注册的ip, port
string ServiceName = configuration.GetSection("Consul")["ServiceName"];
string ip = configuration.GetSection("Consul")["IP"];
int port = int.Parse(configuration.GetSection("Consul")["Port"]);
int weight = int.Parse(configuration.GetSection("Consul")["Weight"]);
client.Agent.ServiceRegister(new AgentServiceRegistration()
{
ID = $"{configuration["ServiceName"]}-{Guid.NewGuid()}",//唯一的
Name = serviceName,//组(服务)名称(动态)
Address = ip,
Port = port,//不同的端口=>不同的实例
Tags = new string[] { weight.ToString() },//标签
Check = new AgentServiceCheck()//服务健康检查
{
Interval = TimeSpan.FromSeconds(12),//间隔1s一次 检查
HTTP = $"http://{ip}:{port}/api/health/check",
Timeout = TimeSpan.FromSeconds(5),//检测等待时间
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(20)//失败后多久移除
}
});
Console.WriteLine($"{ip}:{port}--weight:{weight}");
}
}
}
3)配置注册服务 Program.cs
//注册服务Consul名称
builder.Configuration.ConsulExtend(builder.Configuration.GetSection("Consul")["ServiceName"]);
4)创建心跳控制器 HealthController.cs
namespace Micro.Cms.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
[HttpGet("Check")]
public ActionResult Check()
{
return Ok();
}
}
}
2、配置统一认证 IdentityServer4
// 注册认证相关组件和配置defaultScheme为Bearer
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
// 指定要接入的授权服务器地址
options.Authority = "http://127.0.0.1:5001";
// 在验证token时,不验证Audience
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
// 不适用Https
options.RequireHttpsMetadata = false;
});
2)启动认证 和 授权 Program.cs
// 注册认证过滤器,在授权过滤器前面 app.UseAuthentication(); // 注册授权过滤器 app.UseAuthorization();
3、配置数据上下文(AddDbContext), Program.cs
//注入 AddDbContext 单例模式
builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
2)配置数据库链接字符串
"ConnectionStrings": {
"DefaultConnection": "Server=127.0.0.1;database=cmsdb;uid=sa;pwd=mssql;TrustServerCertificate=True;"
}
4、配置允许跨域,Program.cs
builder.Services.AddCors(options => {
options.AddPolicy("CustomCorsPolicy", policy => {
// 设定允许跨域的来源,有多个可以用','隔开
policy.WithOrigins("http://api.microsoft-zh.cn") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); });
});
2)启动跨域,Program.cs
app.UseCors("CustomCorsPolicy");
5、初始化日志,Program.cs
builder.Host.UseSerilog();
builder.Host.UseSerilog((builderContext, config) =>
{
config
.MinimumLevel.Warning()
.Enrich.FromLogContext()
.WriteTo.File(Path.Combine("Logs", @"Log.txt"), rollingInterval: RollingInterval.Day);
});
6、使用Areas MVC
app.MapRazorPages();
app.MapControllerRoute(
name: "areaRoute",
pattern: $"{{area:exists}}/{{controller=Home}}/{{action=Index}}/{{id?}}");
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
7、自定义属性验证
using System.ComponentModel.DataAnnotations;
namespace Micro.Bpm.Filters
{
/// <summary>
/// 是否是英文字母、数字组合
/// </summary>
public class CustomValidationAttribute : ValidationAttribute
{
/// <summary>
/// 默认的错误提示信息
/// </summary>
private const string error = "请输入正确参数信息";
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//这里是验证的参数的逻辑 value是需要验证的值 而validationContext中包含了验证相关的上下文信息 这里我是有一个自己封装的验证格式的FormatValidation类
if (!FormatValidation.IsSafeSqlString(value as string))
//不成功 提示验证错误的信息
return new ValidationResult(ErrorMessage ?? error);
return ValidationResult.Success;
}
}
}
调用方式:
[HttpGet("FormGet")]
public ActionResult FormGet([CustomValidation][FromQuery] string formCode)
{
var dt = _service.DataFormGet(formCode);
return Ok(JsonConvert.SerializeObject(dt));
}
8、统一输出格式
using Micro.Ids.Utils;
using System.Net.Http;
using System.Text.Json;
namespace Micro
{
/// <summary>
/// 请求响应统一消息
/// </summary>
public class ResponseMessage
{
/// <summary>
///错误码
/// </summary>
public ErrorCode Code { get; set; }
/// <summary>
///错误信息
/// </summary>
public object? Message { get; set; }
/// <summary>
///数据信息
/// </summary>
public object? Data { get; set; }
/// <summary>
///请求地址
/// </summary>
public string? Request { get; set; }
public ResponseMessage() { }
public ResponseMessage(ErrorCode errorCode)
{
Code = errorCode;
}
public ResponseMessage(ErrorCode errorCode, object message)
{
Code = errorCode;
Message = message ?? throw new ArgumentNullException(nameof(message));
}
public ResponseMessage(ErrorCode errorCode, object data, object message)
{
Code = errorCode;
Data = data;
Message = message ?? throw new ArgumentNullException(nameof(message));
}
public static ResponseMessage Success(string message = "操作成功")
{
return new ResponseMessage(ErrorCode.Success, message);
}
public static ResponseMessage Success(object data, string message = "操作成功")
{
return new ResponseMessage(ErrorCode.Success, data, message);
}
public static ResponseMessage Fail(string message = "操作失败")
{
return new ResponseMessage(ErrorCode.Fail, message);
}
public static ResponseMessage Error(string message = "异常错误")
{
return new ResponseMessage(ErrorCode.Error, message);
}
/*
public override string ToString()
{
// 小驼峰序列化
var setting = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
return JsonSerializer.Serialize(this, setting);
}*/
}
}
9、异常处理中间件
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate next; public ErrorHandlingMiddleware(RequestDelegate next) { this.next = next; }
public async Task Invoke(HttpContext context)
{
try
{
await next(context);
}
catch (Exception ex)
{
var statusCode = context.Response.StatusCode;
if (ex is ArgumentException) { statusCode = 200; }
await HandleExceptionAsync(context, statusCode, ex.Message);
}
finally
{
var statusCode = context.Response.StatusCode; var msg = "";
if (statusCode == 401) { msg = "未受权"; }
else if (statusCode == 404) { msg = "未找到服务"; }
else if (statusCode == 502) { msg = "请求错误"; }
else if (statusCode != 200) { msg = "未知错误"; }
if (!string.IsNullOrWhiteSpace(msg)) { await HandleExceptionAsync(context, statusCode, msg); }
}
}
//异常错误信息捕获,将错误信息用Json方式返回
private static Task HandleExceptionAsync(HttpContext context, int statusCode, string msg)
{
var result = JsonConvert.SerializeObject(new
{
Success = false,
Msg = msg,
Type = statusCode.ToString()
});
context.Response.ContentType = "application/json;charset=utf-8"; return context.Response.WriteAsync(result);
}
}
//扩展方法
public static class ErrorHandlingExtensions
{
public static IApplicationBuilder UseErrorHandling(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ErrorHandlingMiddleware>();
}
}
Program.cs 调用
//异常处理中间件
app.UseErrorHandling(); app.UseMiddleware(typeof(ErrorHandlingMiddleware));
10、自定错误异常(全局)
public class CustomExceptionFilter : IAsyncExceptionFilter
{
private readonly ILogger<CustomExceptionFilter> _logger;
public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
{
_logger = logger;
}
public async Task OnExceptionAsync(ExceptionContext context)
{
_logger.LogError(context.Exception, "An error occurred.");
if (!context.ExceptionHandled)
{
context.Result = new ViewResult { ViewName = "Error" };
context.ExceptionHandled = true;
}
await Task.CompletedTask;
}
}
Program.cs 调用
builder.Services.AddMvc(options =>
{
options.Filters.Add<CustomExceptionFilter>();
});
builder.Services.Configure<ApiBehaviorOptions>(options => {
options.InvalidModelStateResponseFactory = actionContext =>
{
//获取验证失败的模型字段
var errors = actionContext.ModelState
.Where(e => e.Value.Errors.Count > 0)
.Select(e => e.Value.Errors.First().ErrorMessage)
.ToList();
var str = string.Join("|", errors);
//设置返回内容
var result = new
{
code = 12001,
body = false,
msg = str
};
return new BadRequestObjectResult(result);
};
});

浙公网安备 33010602011771号