#c# #asp.net-web-api #owin
#c# #asp.net-веб-api #owin
Вопрос:
У меня есть класс Owin middleware, который я использую. Цель состоит в том, чтобы перезаписать тело ответа при обнаружении кода состояния HTTP 401, 403 или 405 и заменить тело объектом JSON. Пока это мой метод:
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403 || context.Response.StatusCode == 405)
{
var owinResponse = context.Response;
var owinResponseStream = owinResponse.Body;
var responseBuffer = new MemoryStream();
owinResponse.Body = responseBuffer;
string message;
switch (context.Response.StatusCode)
{
case 401:
message = "unauthorized request";
break;
case 403:
message = "forbidden request";
break;
default:
message = "request not allowed";
break;
}
var newResponse = new ResponseMessage<string>
{
IsError = true,
StatusCode = (HttpStatusCode) Enum.Parse(typeof(HttpStatusCode), context.Response.StatusCode.ToString()),
Data = null,
Message = message
};
var customResponseBody = new StringContent(JsonConvert.SerializeObject(newResponse));
var customResponseStream = await customResponseBody.ReadAsStreamAsync();
await customResponseStream.CopyToAsync(owinResponseStream);
owinResponse.ContentType = "application/json";
owinResponse.ContentLength = customResponseStream.Length;
owinResponse.StatusCode = 200;
owinResponse.Body = owinResponseStream;
}
}
По большей части это работает, однако тело ответа добавляется вместо замены. Например, в случае ошибки 401 тело ответа является:
{"message":"Authorization has been denied for this request."}
{"IsError":true,"StatusCode":401,"Data":null,"Message":"unauthorized request"}
вместо:
{"IsError":true,"StatusCode":401,"Data":null,"Message":"unauthorized request"}
Я уверен, что это как-то связано с тем, как я пишу в тело ответа, но пока ничего не решило проблему.
Любые предложения будут высоко оценены.
Спасибо
Ответ №1:
Потому что вы пишете приведенный ниже код после await Next.Invoke(context);
await Next.Invoke(context);
if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403 || context.Response.StatusCode == 405)
{
var owinResponse = context.Response;
var owinResponseStream = owinResponse.Body;
var responseBuffer = new MemoryStream();
owinResponse.Body = responseBuffer;
Это неправильно.
Следующий фрагмент кода будет работать так, как вы хотите:
public override async Task Invoke(IOwinContext context)
{
var owinResponse = context.Response;
var owinResponseStream = owinResponse.Body;
var responseBuffer = new MemoryStream();
owinResponse.Body = responseBuffer;
await Next.Invoke(context);
if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403 || context.Response.StatusCode == 405)
{
string message;
switch (context.Response.StatusCode)
{
case 401:
message = "unauthorized request";
break;
case 403:
message = "forbidden request";
break;
default:
message = "request not allowed";
break;
}
var newResponse = new ResponseMessage<string>
{
IsError = true,
StatusCode = (HttpStatusCode) Enum.Parse(typeof(HttpStatusCode), context.Response.StatusCode.ToString()),
Data = null,
Message = message
};
var customResponseBody = new StringContent(JsonConvert.SerializeObject(newResponse));
var customResponseStream = await customResponseBody.ReadAsStreamAsync();
await customResponseStream.CopyToAsync(owinResponseStream);
owinResponse.ContentType = "application/json";
owinResponse.ContentLength = customResponseStream.Length;
owinResponse.StatusCode = 200;
owinResponse.Body = owinResponseStream;
}
}
Ответ №2:
Когда вы сначала устанавливаете тело ответа в поток памяти, курсор (текущая позиция ) переместится в его конец. owinResponse.Body = responseBuffer;
в результате мы получили {"message":"Authorization has been denied for this request."}
сохраненные и указывающие курсор точки в конце.
Опять же, в конце вашего метода вы пишете новый ответ owinResponse.Body = owinResponseStream;
, который содержит сообщение {"IsError":true,"StatusCode":401,"Data":null,"Message":"unauthorized request"}
Поскольку текущая позиция указывает на конец потока, следовательно, она будет добавлена.
Попробуйте удалить первый набор тела поскольку вам не нужно исходное ответное сообщение. owinResponse.Body = responseBuffer;