How to publish message without waiting for response RabbitMQ - c#

I'm new to RabbitMq and I just followed internet resource as a tutorial. here I have created two separate API for OrderRequest and OrderConsume. from the order request, I'm calling something like this.
IRequestClient<OrderRequest> _client;
public OrderRepo(IRequestClient<OrderRequest> requestClient)
{
_client = requestClient;
}
public async Task<string> GetOrderList(OrderRequest orderRequest)
{
string datas = "";
try
{
using (var request = _client.Create(orderRequest))
{
var response = await request.GetResponse<OrderReponse>();
datas = response.Message.orderName;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
return datas;
}
and from the OrderConsume, I did something like this.
public class OrderConsumer : IConsumer<OrderRequest>
{
public Task Consume(ConsumeContext<OrderRequest> context)
{
OrderReponse request = new();
try
{
var data = context.Message.orderName + " HelloWorld";
request.orderName = data;
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.Message);
throw;
}
return Task.CompletedTask;
}
}
When I debugging the code Consume part working fine, but here you can see, I'm not passing any response from there. there for from the request API. I'm getting time out error.
Timeout waiting for response, RequestId: a1670000-a53b-c025-bd0b-08d9d52ca58a.
Actually I don't need any response from Consumer side, and just wanted to pass the request to consumer. I think I need to change my code here?
using (var request = _client.Create(orderRequest))
{
var response = await request.GetResponse<OrderReponse>();
datas = response.Message.orderName;
}
is it correct? but actually i don't know how to do it. please help me to solve this.

If your order command does not require a response, don't use the request client. Just publish the command and forget about it.
IPublishEndpoint _publishEndpoint;
public OrderRepo(IPublishEndpoint publishEndpoint)
{
_publishEndpoint = publishEndpoint;
}
public async Task<string> GetOrderList(OrderRequest orderRequest)
{
string datas = "";
try
{
await _publishEndpoint.Publish<OrderRequest>(orderRequest);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
return datas;
}
Of course, in your original code you were actually using the response, so...

Related

How to handle error 500 and respond from custom middleware class in asp.net core web api?

I have a custom middleware class in asp.net web api which processes and sends a response to the client.
It is class controller action which actually return a response.
During execution of this GetT function in controller it breaks and returns a ninternal server error 500. We want to handle the internal error 500 and what the exception type was.
We still want to send status code 500 error but with a custom error message in the original Response.
Class TResponse, apart from sending data, also sends whether it succeeds or not and some other message can be set if there was a 500 error. But we still want to send this TResponse even after 500 error.
Controller/Action:
public async Task<ActionResult<TResponse>> GetT(TRequest request)
{
.............
TResponse response = await _tService.GetT(request);
.......
return Ok(response).
}
public class ResponseMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var originalBodyStream = context.Response.Body;
try
{
using var memoryStream = new MemoryStream();
context.Response.Body = memoryStream;
await next(context);
memoryStream.Position = 0;
var reader = new StreamReader(memoryStream);
var responseBody = await reader.ReadToEndAsync();
memoryStream.Position = 0;
await memoryStream.CopyToAsync(originalBodyStream);
var requestTelemetry = context.Features.Get<RequestTelemetry>();
requestTelemetry?.Properties.Add("ResponseBody", responseBody);
Log.Information(responseBody);
}
catch (Exception ex)
{
string exType = ex.GetType().ToString();
context.Response.StatusCode = 500;
if (exType=="sql") //Data query error
{
context.Response.ContentType = "application/json";
TResponse response = new TResponse();
// ???????????
}
finally
{
context.Response.Body = originalBodyStream;
}
}
}
So in the catch block of the InvokeAsync(), I added a try catch block to handle 500 error.
I am facing a challenge how to convert a TResponse (after settiing some info on it for 500 related error) object into original body response which somehow gets processed through memory stream just like when there is no error.
In Short, how to handle 500 error and send TResponse from catch block?
I think we want to execute the same line of code in InvokeAsync() even after handling 500 error in order to send correct response.
Hi #user21225864 you mentioned you want to send status code 500 for internal server error which means exception accrued on server side. To return a custom response this might be one approach. Regardless of where you catch exception. Custom response is returned if exception accrued or not.
Controller:
[HttpGet]
[Route("[action]")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<CompanyDto>))]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetAll()
{
var companies = await _compService.GetAllAsync();
return Ok(companies);
}
CompanyService:
public async Task<ServiceResponse<List<CompanyDto>>> GetAllAsync()
{
ServiceResponse<List<CompanyDto>> _response = new();
List<CompanyDto> _listCompanyDto = new List<CompanyDto>();
try
{
//Get set of records from repo
var CompanyList = await _compRepo.GetAllAsync();
var CompanyListDto = new List<CompanyDto>();
foreach (var item in CompanyList)
{
CompanyListDto.Add(_mapper.Map<CompanyDto>(item));
}
_response.Success = true;
_response.Message = "OK";
_response.Data = CompanyListDto;
return _response;
}
catch (Exception)
{
_response.Success = false;
_response.Message = "Error";
_response.Error = "Ininternal server error 500";
}
return _response;
}
Custom Response:
/// <summary>
/// Generic wraper around web api service responce.
/// </summary>
/// <typeparam name="T"></typeparam>
public class ServiceResponse<T>
{
public T? Data { get; set; }
public bool Success { get; set; }
public string? Message { get; set; }
public string? Error { get; set; }
}

How send different client certificates on different requests with a single instance of HttpClient in .Net Core?

The recommendation for HttpClient is to reuse a single instance. But from the API, it looks like the way to add certificates is on the instance, not per request. If we add two certificates, how can we make sure that "cert 1" is only sent to "one.somedomain.com", for example?
//A handler is how you add client certs (is there any other way?)
var _clientHandler = new HttpClientHandler();
//Add multiple certs
_clientHandler.ClientCertificates.Add(cert1);
_clientHandler.ClientCertificates.Add(cert2);
_clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
//Pretend this is our long-living HttpClient
var client = new HttpClient(_clientHandler);
//Now if we make a post request, will both certs be used?
using (HttpResponseMessage response = _client.PostAsync("https://one.somedomain.com", content).Result)
{
//...elided...
}
Sorry. End of year a lot of work.
Yo can try to implement somthing like this:
public class CustomHttpHandler : HttpClientHandler
{
private readonly Dictionary<string, X509Certificate> _certMap;
public CustomHttpHandler():base()
{
_certMap = new Dictionary<string, X509Certificate>() { { "server1name", new X509Certificate("cert1") }, { "server2name", new X509Certificate("cert2") } };
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
string serverName = request.RequestUri.Host;
if (ClientCertificates.Contains(_certMap[serverName]))
{
try
{
var response = await base.SendAsync(request, cancellationToken);
return response;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
throw;
}
}
else
{
ClientCertificates.Clear();
ClientCertificates.Add(_certMap[serverName]);
try
{
var response = await base.SendAsync(request, cancellationToken);
return response;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
throw;
}
}
}
}
Just an idea, not tested it.
Or, alternatively you can use Headers collection in RequestMessage instance.
This article cover the topic: https://damienbod.com/2019/09/07/using-certificate-authentication-with-ihttpclientfactory-and-httpclient/
That is the recommendation, however, you can use "using" statements.
Once HttpClient is an IDisposable, you should use something like
using(var client = new HttpClient(_clientHandler))
{
//Your code here
}

Post Method HTTP response is 200 but no data changed In web api

I want to post data form my code but no data changed . when I debug the code it got me 200 which mean code is good . I tried to test in fiddler and data is changed successfully . I want to know where is the wrong ?
this is my service including url
public static async Task<string> PostOrderAsync(MachinePostModel Order)
{
try
{
var client = new HttpClient();
string data = JsonConvert.SerializeObject(Order);
var content = new StringContent(data, Encoding.UTF8, "application/json");
var response = await client.PostAsync("http://94.205.253.150:2016/api/JobOrder", content);
return data;
}
catch
{
return null;
}
}
and this is the step where i send order object
private async Task<bool> AcceptPostOrder()
{
MachinePostModel OrderDetails = new MachinePostModel();
try
{
OrderDetails.ID = 1163;
OrderDetails.joStatus = "should to wait";
OrderDetails.remarks = "hello remarks";
var Client = await Services.MachineTestPostService.PostOrderAsync(OrderDetails);
return true;
}
catch (Exception exc)
{
await MachineTestOrderView.machineobj.DisplayAlert("Alert", exc.Message, "OK");
return false;
}
}
finally my model
public class MachinePostModel
{
public int ID { get; set; }
public string remarks { get; set; }
public string joStatus { get; set; }
}
Get link to check if data is changed
http://94.205.253.150:2016/api/JobOrder/Get?regId=1&driverID=35&status=All%20Status
There are some mistakes in your code. Firstly, decorate your action with HttpPost attribute and add a parameter for sent complex object.
[HttpPost]
private async Task<bool> AcceptPostOrder(MachinePostModel Order)
{
MachinePostModel OrderDetails = new MachinePostModel();
try
{
OrderDetails.ID = 1163;
OrderDetails.joStatus = "should to wait";
OrderDetails.remarks = "hello remarks";
var Client = await Services.MachineTestPostService.PostOrderAsync(OrderDetails);
return true;
}
catch (Exception exc)
{
await MachineTestOrderView.machineobj.DisplayAlert("Alert", exc.Message, "OK");
return false;
}
}
And, there is no routing definition as api/JobOrder, so I assume that you are trying to post the data AcceptPostOrder method. Change the request endpoint;
var response = await client.PostAsync("http://94.205.253.150:2016/api/AcceptPostOrder", content);

Showing custom error message on web browser

I have created an ASP.NET Web API which calls a java web server to retrieve data. When the java web server is down, i want the Web API to show an error message: {"ErrorMessage:" Server is down} What are the codes that i should add to achieve the custom error message to be shown on the browser?
Here are my codes:
RestfulClient.cs
public class RestfulClient
{
private static HttpClient client;
private static string BASE_URL = "http://localhost:8080/";
static RestfulClient()
{
client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> addition(int firstNumber, int secondNumber)
{
try
{
var endpoint = string.Format("addition/{0}/{1}", firstNumber, secondNumber);
var response = await client.GetAsync(endpoint);
return await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
//What do i have to code here?
}
return null;
}
}
AdditionController.cs
public class Temp
{
public string firstNumber { get; set; }
public string secondNumber { get; set; }
public string sum { get; set; }
}
public class AdditionController : ApiController
{
private RestfulClient restfulClient = new RestfulClient();
public async Task<IHttpActionResult> Get(int firstNumber, int secondNumber)
{
var result = await restfulClient.addition(firstNumber, secondNumber);
var resultDTO = JsonConvert.DeserializeObject<Temp>(result);
return Json(resultDTO);
}
}
Someone please do help me, thank you so much.
If you catch an exception of type Exception and then decide the server you called is down, that would not be true. Something may go wrong within your own code before you call the other service or after the other service has returned successfully. Therefore, you need to be careful how you make that decision.
Having said that it is still hard to say when you can make that decision with confidence: Is the calling service returning the correct message etc.
Anyhow, you can do something similar to this:
try
{
// ...
}
catch (System.Net.WebException ex)
{
if (ex.Status == System.Net.WebExceptionStatus.ConnectFailure)
{
// To use these 2 commented out returns, you need to change
// your method's return type to Task<IHttpActionResult>
// return Content(System.Net.HttpStatusCode.ServiceUnavailable, "Unavilable.");
// return StatusCode(System.Net.HttpStatusCode.ServiceUnavailable);
return "Unavailable"
}
}
catch(Exception ex)
{
// You could be here because something went wrong in your server,
// or the server you called which was not caught by the catch above
// because it was not WebException. Make sure to give it some
// thought.
// You need to change
// your method's return type to Task<IHttpActionResult> or
// just return a string.
return StatusCode(System.Net.HttpStatusCode.InternalServerError);
}

HttpResponseMessage Content Property in Compact Framework

I am building a .NET 4.5 MVC 4 Web API that will have publicly exposed Controller Methods that I wish to secure access to. I have created a Action Filter Attribute to check for a properly encoded RSA token shown below gutted for brevity:
public class TokenValidationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
try
{
//authorize user
}
catch (Exception)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden)
{
Content = new StringContent("Unauthorized User")
};
}
}
}
And then in my .NET 3.5 CF application I would do the following:
public static List<string> GetAvailableProjectIds()
{
var idList = new List<string>();
var url = "the url";
var req = CreateRequest(url, true);
try
{
using (var response = (HttpWebResponse)req.GetResponse())
{
//do something with the resonse
}
}
catch (Exception ex)
{
}
return idList;
}
The Exception that is caught is a WebException and contains the correct 403 Forbiden Status Code. But nothing more helpful that I can find.
Is there a way to get at the Content property so I can display to the end user that they tried authenticating with an "Unauthorized User"?
I never really liked that behavior, that it uses exceptions when the communication was just fine. Try adding this extension method:
private static HttpResponse GetAnyResponse(this HttpRequest req)
{
HttpResponse retVal = null;
try
{
retVal = (HttpWebResponse)req.GetResponse()
}
catch (WebException webEx)
{
retVal = webEx.Response;
}
catch (Exception ex)
{
// these are the "bad" exceptions, let them pass
throw;
}
return webEx;
}
And then change your code to this:
using (var response = (HttpWebResponse)req.GetAnyResponse())
{
//do something with the resonse
}

Categories