Я перехватываю HTTP-запрос, используя пользовательское промежуточное программное обеспечение, и хочу зарегистрировать запрос и ответ на файл. json с помощью NLog. Проблема возникает, когда я хочу десериализовать тело запроса / ответа из строки в объект пользовательского класса , а затем методы POST / PUT / DELETE не работают.
Почтальон при бросках метода POST: 500 Внутренняя ошибка сервера
Angular Приложение при бросках метода POST: Доступ к XMLHttpRequest в myValidEndpoint из источника 'http://localhost: 4200 ' заблокировано политикой CORS: в запрошенном ресурсе отсутствует заголовок 'Access-Control-Allow-Origin'.
Если я регистрирую тело запроса / ответа как строку, каждый http-метод работает нормально. Вот код:
Program.cs
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
LogManager.LoadConfiguration(String.Concat(Directory.GetCurrentDirectory(), "/nlog.config"));
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public HttpConfiguration Config { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IDrzavaService, DrzavaService>();
services.AddTransient<IGradService, GradService>();
services.AddEntityFrameworkNpgsql().AddDbContext<DrzavedbContext>(opt => opt.UseNpgsql(Configuration.GetConnectionString("DrzaveConnection")))
.AddUnitOfWork<DrzavedbContext>();
services.AddControllers().AddNewtonsoftJson();
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("http://localhost:4200").AllowAnyHeader().AllowAnyMethod();
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMyMiddleware();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<ExceptionMiddleware>();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
nlog .config
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Trace"
internalLogFile="./GlobalErrorHandlingLogs/internal_logs/internallog.txt">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target name="ExceptionMiddleware" xsi:type="File"
fileName="./../../../GlobalErrorHandlingLogs/logs/${shortdate}_logfile.txt"
layout="${longdate} ${level:uppercase=true} ${message} ${exception:format=tostring}"/>
<target name="file" xsi:type="AutoFlushWrapper">
<target name="RequestLoggingMiddleware" xsi:type="File"
fileName="./../../../HttpRequestHandlingLogs/logs/${shortdate}_HttpLog.json">
<layout xsi:type="JsonLayout" >
<attribute name="level" layout="${level:upperCase=true}"/>
<attribute name="eventProperties" encode="false">
<layout type='JsonLayout' includeAllProperties="true" maxRecursionLimit="5"/>
</attribute>
</layout>
</target>
</target>
</targets>
<rules>
<logger name="*" minlevel="Error" writeTo="ExceptionMiddleware" />
<logger name="*" minlevel="Info" maxlevel="Info" writeTo="RequestLoggingMiddleware" />
</rules>
</nlog>
RequestLoggingMiddleware.cs
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly Logger _logger;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
Stopwatch _stopwatch;
public RequestLoggingMiddleware(RequestDelegate next)
{
_next = next;
_logger = LogManager.GetCurrentClassLogger();
_recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
}
public async Task Invoke(HttpContext context)
{
await LogRequest(context);
await LogResponse(context);
}
private async Task LogRequest(HttpContext context)
{
_stopwatch = Stopwatch.StartNew();
context.Request.Headers.Add("X-Request-Guid", Guid.NewGuid().ToString());
context.Request.EnableBuffering();
await using var requestStream = _recyclableMemoryStreamManager.GetStream();
await context.Request.Body.CopyToAsync(requestStream);
string bodyString = ReadStreamInChunks(requestStream);
List<BodyItem> body = JsonConvert.DeserializeObject<List<BodyItem>>(bodyString);
RequestModel requestModel = new RequestModel()
{
requestStart = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff tt"),
method = context.Request.Method,
schema = context.Request.Scheme,
host = context.Request.Host.ToString(),
path = context.Request.Path,
requestBody = body,
requestGuid = context.Request.Headers["X-Request-Guid"]
};
_logger.Info("{request}", requestModel);
context.Request.Body.Position = 0;
}
private static string ReadStreamInChunks(Stream stream)
{
const int readChunkBufferLength = 4096;
stream.Seek(0, SeekOrigin.Begin);
using var textWriter = new StringWriter();
using var reader = new StreamReader(stream);
var readChunk = new char[readChunkBufferLength];
int readChunkLength;
do
{
readChunkLength = reader.ReadBlock(readChunk, 0, readChunkBufferLength);
textWriter.Write(readChunk, 0, readChunkLength);
} while (readChunkLength > 0);
return textWriter.ToString();
}
private async Task LogResponse(HttpContext context)
{
context.Response.Headers.Add("X-Request-Guid", context.Request.Headers["X-Request-Guid"].ToString());
var originalBodyStream = context.Response.Body;
await using var responseBody = _recyclableMemoryStreamManager.GetStream();
context.Response.Body = responseBody;
await _next(context);
context.Response.Body.Seek(0, SeekOrigin.Begin);
string bodyStream = await new StreamReader(context.Response.Body).ReadToEndAsync();
List<BodyItem> body = JsonConvert.DeserializeObject<List<BodyItem>>(bodyStream);
context.Response.Body.Seek(0, SeekOrigin.Begin);
ResponseModel responseModel = new ResponseModel()
{
requestEnd = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff tt"),
responseBody = body,
responseGuid = context.Response.Headers["X-Request-Guid"],
statusCode = context.Response.StatusCode.ToString(),
requestDuration = _stopwatch.ElapsedMilliseconds
};
_logger.Info("{response}", JsonConvert.SerializeObject(responseModel));
await responseBody.CopyToAsync(originalBodyStream);
}
}
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggingMiddleware>();
}
}
BodyItem.cs
[JsonObject]
class BodyItem
{
[JsonProperty]
public int id { get; set; }
[JsonProperty]
public string name { get; set; }
[JsonProperty]
public int? population { get; set; }
[JsonProperty]
public int? countryId{ get; set; }
}
RequestModel.cs
class RequestModel
{
public string requestStart { get; set; }
public string method { get; set; }
public string schema { get; set; }
public string host { get; set; }
public string path { get; set; }
public List<BodyItem> requestBody { get; set; }
public string requestGuid { get; set; }
}
ResponseModel.cs
class ResponseModel
{
public string requestEnd { get; set; }
public List<BodyItem> responseBody { get; set; }
public string responseGuid { get; set; }
public string statusCode { get; set; }
public float requestDuration { get; set; }
}