I'm trying to set up a RoutingSlipResponseProxy that will prevent a response from being sent if there is no RequestId. I am trying to do this by overriding the Consume method in my RoutingSlipResponseProxy, like so:
public class MigrateResponseProxy : RoutingSlipResponseProxy<IMigrationRequested, IMigrationComplete>
{
public new async Task Consume(ConsumeContext<RoutingSlipCompleted> context)
{
var isRequest = context.Message.Variables.ContainsKey("RequestId");
if (!isRequest)
return;
var request = context.Message.GetVariable<IMigrationRequested>("Request");
var requestId = context.Message.GetVariable<Guid>("RequestId");
Uri responseAddress = null;
if (context.Message.Variables.ContainsKey("ResponseAddress"))
responseAddress = context.Message.GetVariable<Uri>("ResponseAddress");
if (responseAddress == null)
throw new ArgumentException($"The response address could not be found for the faulted routing slip: {context.Message.TrackingNumber}");
var endpoint = await context.GetResponseEndpoint<IMigrationComplete>(responseAddress, requestId).ConfigureAwait(false);
var response = await CreateResponseMessage(context, request);
await endpoint.Send(response).ConfigureAwait(false);
}
... remaining code ...
}
This is basically the same code as the original method, except with a check for the RequestId at the beginning. However, when debugging through the code, it seems as though this overridden method is never getting called, and instead the parent method is getting called. Is there something I might be missing here? Any help would be appreciated.
The methods aren't virtual, so you won't be able to override them. In this case, you'd be better of copying the proxy code into your own project instead of using the implementation that's included with MassTransit.
You're welcome to submit a PR to make those methods virtual.
Related
I use the following function which is all well and fine but i basically do the same operation about 20 times. For various end points of an api I am hitting how would one make this routing more Generic in the ability to pass and return type OF T.
public async Task<List<StockItem>> GetStockDataFromSage()
{
StockItem stockitems = new StockItem();
string content = "";
List<StockItem> result = new List<StockItem>();
var uri = new Uri(string.Format(Constants.GetStockItems, string.Empty));
var response = await _client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<StockItem>>(content);
}
return result;
}
Edit 1
I am trying to use the below however I am getting an error
public async Task<List<StockItem>> GetStockItemInfo()
{
return await dataTransfer.GetDataFromSageService(Constants.GetStockItems, string.Empty)) ?? new List<StockItem>();
}
Severity Code Description Project File Line Suppression State
Error CS1061 'StockTakeDT' does not contain a definition for 'GetStockDataFromSage' and no accessible extension method 'GetStockDataFromSage' accepting a first argument of type 'StockTakeDT' could be found (are you missing a using directive or an assembly reference?) StockAppDL D:\Git\Repos\StockApp\FStockApp\StockAppDal\StockDatabase.cs 76 Active
Your objective here appears to be to call an endpoint and get the results back into an object you can use. If the call is successful, you return the result and if it fails, you return an empty list.
We can abstract that logic out into a generic method that accepts a url and parameters and returns an object.
public async Task<T> GetObjectFromEndpoint<T>(string url, params string[] args)
where T : class
{
var uri = new Uri(string.Format(url, args));
var response = await _client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(content);
}
return default(T);
}
Now your GetStockDataFromSage function passes in the information unique to this call, namely the url, parameters, and generic type for the results. If the result is null, GetStockDataFromSage returns an empty list of StockItems
public async Task<List<StockItem>> GetStockDataFromSage()
{
return (await GetObjectFromEndpoint<List<StockItem>>(Constants.GetStockItems, string.Empty)) ?? new List<StockItem>();
}
Any time you are trying to minimize repetition, you want to look at what is specific to this call and what is more general. i.e List<StockItem>, the url, and possibly the parameter are unique, but the rest of the code is very general.
Caution: This method of returning a default value when the api call fails can lead to hard-to-diagnose issues where you will be unable to differentiate between an empty list and a failed api call. I recommend adding some logging for failed api calls and perhaps looking at ways to inform the calling code that the result was in error.
The Situation
I'm working on a OAuth2 Api Wrapper. Some api routes are for logged people and some for anonymous and logged.
Here is an example of one method in my wrapper :
public async Task<UploadListResponse> List(bool pagination = false, int page = 1, int limit = 10)
{
var request = UploadRequests.List(pagination, page, limit);
var cancellationTokenSource = new CancellationTokenSource();
var restResponse = await Context.Client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
return restResponse.Handle<UploadListResponse>();
}
I build a request with all parameter set up then execute the request and then handle the answer in case I have an api error and then output an object containing all the data that request gave me.
The problem
With OAuth2, when you log to the API you'll receive an access token and a refresh token. If your access token is expired you have to contact the api with your refresh token to get a fresh new access token.
As I said earlier some of my method needs you to be logged but if your access token is expired I want to try to refresh token before throwing an exception like with this method :
public async Task<bool> NeedRelog()
{
try
{
var validAuth = await ValidAuth();
}
catch
{
try
{
var refresh = await Refresh(Context.Client.Config.RefreshToken);
}
catch
{
return true;
}
}
return false;
}
ValidAuth check with the API if you are logged and if I have an exception then I'll try to refreshToken.
I want to tag method that need logged to call NeedRelog() and those who aren't tag to not call it.
I may just do it in every method but it wouldn't be clean.
What I've done so far
I've found a great tool : PostSharp that seems to fit my needs.
I've started to do a checkLog aspect like this :
[Serializable]
public class CheckLog : OnMethodBoundaryAspect, IOnStateMachineBoundaryAspect
{
public CheckLog()
{
ApplyToStateMachine = false;
}
public override void OnEntry(MethodExecutionArgs args)
{
var instance = (ApiService)args.Instance;
var res = instance.Parent.OAuth.NeedRelog().Result;
if (!res)
{
args.Exception = new Exception("Need to relog");
args.FlowBehavior = FlowBehavior.Return;
}
}
}
Where I'm stuck
The Main problem is with the call to my NeedRelog() Method. Due to the fact this is an async method I'm struggling to make my aspect await for it.
If my OnEntry method is async then It won't block the call if you are not logged.
If my OnEntry method is not async and I wait for needLog it freeze and nothing happen.
I really want to know to use this kind of "conditional method call" with postsharp, it looks awesome but the fact is after looking for hours in the documentation I didn't find a way to do what I want.
I'm starting to ask myself if it is even possible to achieve what I'm aiming to do.
Did you try using a way to make the call synchronous maybe with something like this stackoverflow.com/a/25097498/3131696 ? – M22an 5 hours ago
As I can't mark a comment as answering a question I quote your comment to make this question answered as it is said here : link
Thanks you for this M22an.
For one of my projects I want to develop a library that can be used in different platforms (Desktop, Mobile, Surface, etc). Hence have opted Porable Class Library.
I am developing a class for calling different API calls' using HttpClient. I am stuck with how to call the method, response and work around. This is my code :-
public static async Task<JObject> ExecuteGet(string uri)
{
using (HttpClient client = new HttpClient())
{
// TODO - Send HTTP requests
HttpRequestMessage reqMsg = new HttpRequestMessage(HttpMethod.Get, uri);
reqMsg.Headers.Add(apiIdTag, apiIdKey);
reqMsg.Headers.Add(apiSecretTag, ApiSecret);
reqMsg.Headers.Add("Content-Type", "text/json");
reqMsg.Headers.Add("Accept", "application/json");
//response = await client.SendAsync(reqMsg);
//return response;
//if (response.IsSuccessStatusCode)
//{
string content = await response.Content.ReadAsStringAsync();
return (JObject.Parse(content));
//}
}
}
// Perform AGENT LOGIN Process
public static bool agentStatus() {
bool loginSuccess = false;
try
{
API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Wait();
// ACCESS Response, JObject ???
}
catch
{
}
finally
{
}
Like ExecuteGet, I will also create for ExecutePost. My query is from ExecuteGet, if (1) I pass JObject on parsing when IsSuccessStatusCode only, then how can I know about any other errors or messages to inform the user. (2) If I pass response, then how do I assign it here
response = API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Wait();
that is giving error.
What would be the best approach to handle this situation ? And I got to call multiple API's, so different API will have different result sets.
Also, can you confirm that designing this way and adding PCL reference I will be able to access in multiple projects.
UPDATE :-
As mentioned in below 2 answers I have updated my code. As mentioned in the provided link I am calling the from the other project. This is my code :-
Portable Class Library :-
private static HttpRequestMessage getGetRequest(string url)
{
HttpRequestMessage reqMsg = new HttpRequestMessage(HttpMethod.Get, url);
reqMsg.Headers.Add(apiIdTag, apiIdKey);
reqMsg.Headers.Add(apiSecretTag, ApiSecret);
reqMsg.Headers.Add("Content-Type", "text/json");
reqMsg.Headers.Add("Accept", "application/json");
return reqMsg;
}
// Perform AGENT LOGIN Process
public static async Task<bool> agentStatus() {
bool loginSuccess = false;
HttpClient client = null;
HttpRequestMessage request = null;
try
{
client = new HttpClient();
request = getGetRequest("http://api.mintchat.com/agent/autoonline");
response = await client.SendAsync(request).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
JObject o = JObject.Parse(content);
bool stat = bool.Parse(o["status"].ToString());
///[MainAppDataObject sharedAppDataObject].authLogin.chatStatus = str;
o = null;
}
loginSuccess = true;
}
catch
{
}
finally
{
request = null;
client = null;
response = null;
}
return loginSuccess;
}
From the other WPF project, in a btn click event I am calling this as follows :-
private async void btnSignin_Click(object sender, RoutedEventArgs e)
{
/// Other code goes here
// ..........
agent = doLogin(emailid, encPswd);
if (agent != null)
{
//agent.OnlineStatus = getAgentStatus();
// Compile Error at this line
bool stat = await MintWinLib.Helpers.API_Utility.agentStatus();
...
I get these 4 errors :-
Error 1 Predefined type 'System.Runtime.CompilerServices.IAsyncStateMachine' is not defined or imported D:\...\MiveChat\CSC
Error 2 The type 'System.Threading.Tasks.Task`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Threading.Tasks, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f89d50a3a'. D:\...\Login Form.xaml.cs 97 21
Error 3 Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly? D:\...\Login Form.xaml.cs 97 33
Error 4 Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly? D:\...\Login Form.xaml.cs 47 28
I tried adding System.Threading.Tasks from the PCL library only, that gave 7 different errors. Where am I going wrong ? What to do to make this working ?
Please guide me on this. Have spend lots of hours figuring the best to develop a library accessible to desktop app & Win Phone app.
Any help is highly appreciative. Thanks.
If you call an async api when making the http calls, you should also expose that async endpoint to the user, and not block the request using Task.Wait.
Also, when creating a third party library, it is recommanded to use ConfigureAwait(false) to avoid deadlocks when the calling code tries to access the Result property or the Wait method. You should also follow guidelines and mark any async method with Async, so the method should be called ExecuteStatusAsync
public static Task<bool> AgentStatusAsync()
{
bool loginSuccess = false;
try
{
// awaiting the task will unwrap it and return the JObject
var jObject = await API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").ConfigureAwait(false);
}
catch
{
}
}
And inside ExecuteGet:
response = await client.SendAsync(reqMsg).ConfigureAwait(false);
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
In case IsSuccessStatusCode is false, you may throw an exception to the calling code to show something went wrong. To do that, you can use the HttpResponseMessage.EnsureSuccessStatusCode which throws an exception if the status code != 200 OK.
Personally, if ExecuteGet is a public API method i would definitely not expose it as a JObject but a strongly typed type.
If you want the result of the task, you need to use the Result property:
var obj = API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Result;
However, it's usually not a good idea to wait synchronously for an async method to complete, because it can cause deadlocks. The better approach is to await the method:
var obj = await API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline");
Note that you need to make the calling method async as well:
public static async Task<bool> agentStatus()
Sync and async code don't play together very well, so async tends to propagate across the whole code base.
I have this code within a request handling method of an ApiController:
if (uri != null)
{
HttpResponseMessage r = Request.CreateResponse(HttpStatusCode.Redirect);
r.Headers.Location = uri;
throw new HttpResponseException(r);
}
The potential problem is that "r" is never disposed (in my code at least).
I could wrap this in a using, but then wouldn't "r" get disposed before the response is streamed to the client?
What is the correct way to handle this?
All the examples I've seen show that you do not have to dispose of the Response.
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent(string.Format("No product with ID = {0}", id)),
ReasonPhrase = "Product ID Not Found"
}
throw new HttpResponseException(resp);
}
return item;
}
Looking at the source code to HttpResponseException, it appears that it populates a Property (HttpResponseMessage Response) with that value and disposing of it would probably cause the HttpResponseMessage either cause an ObjectDisposedException or fail to be delivered to the client.
You'll also notice that in the source code there is a SupressMessage:
[SuppressMessage("Microsoft.Reliability",
"CA2000:Dispose objects before losing scope",
Justification = "Instance is disposed elsewhere")]
Instance is disposed of elsewhere (this is not referring to HttpResponseMesssage, it does not implement IDisposable).
What is the correct way to handle this?
I don't believe any change to your code is required.
For me, "Instance is disposed elsewhere" doesn't means you don't need to deal with it.
My solution is RegisterForDispose so it becomes:
HttpResponseMessage r = Request.CreateResponse(HttpStatusCode.Redirect);
r.Headers.Location = uri;
this.request.RegisterForDispose(r);
throw new HttpResponseException(r);
If I use code like this [just below] to add Message Headers to my OperationContext, will all future out-going messages contain that data on any new ClientProxy defined from the same "run" of my application?
The objective, is to pass a parameter or two to each OpeartionContract w/out messing with the signature of the OperationContract, since the parameters being passed will be consistant for all requests for a given run of my client application.
public void DoSomeStuff()
{
var proxy = new MyServiceClient();
Guid myToken = Guid.NewGuid();
MessageHeader<Guid> mhg = new MessageHeader<Guid>(myToken);
MessageHeader untyped = mhg.GetUntypedHeader("token", "ns");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
proxy.DoOperation(...);
}
public void DoSomeOTHERStuff()
{
var proxy = new MyServiceClient();
Guid myToken = Guid.NewGuid();
MessageHeader<Guid> mhg = new MessageHeader<Guid>(myToken);
MessageHeader untyped = mhg.GetUntypedHeader("token", "ns");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
proxy.DoOtherOperation(...);
}
In other words, is it safe to refactor the above code like this?
bool isSetup = false;
public void SetupMessageHeader()
{
if(isSetup) { return; }
Guid myToken = Guid.NewGuid();
MessageHeader<Guid> mhg = new MessageHeader<Guid>(myToken);
MessageHeader untyped = mhg.GetUntypedHeader("token", "ns");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
isSetup = true;
}
public void DoSomeStuff()
{
var proxy = new MyServiceClient();
SetupMessageHeader();
proxy.DoOperation(...);
}
public void DoSomeOTHERStuff()
{
var proxy = new MyServiceClient();
SetupMessageHeader();
proxy.DoOtherOperation(...);
}
Since I don't really understand what's happening there, I don't want to cargo cult it and just change it and let it fly if it works, I'd like to hear your thoughts on if it is OK or not.
I think your refactored code doesn't put any added-value. Have you taken in account that the OperationContext can be null?
I think this will be a safer approach:
using(OperationContextScope contextScope =
new OperationContextScope(proxy.InnerChannel))
{
.....
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
proxy.DoOperation(...);
}
OperationContextScope's constructor will always cause replacement of the Operation context of the current thread; The OperationContextScope's Dispose method is called which restores the old context preventing problems with other objects on the same thread.
I believe your OperationContext is going to get wiped each time you new the proxy.
You should plan on adding the custom message headers prior to each call. This is good practice in any case as you should prefer per call services and close the channel after each call.
There are a couple patterns for managing custom headers.
You can create the header as part of the constructor to the proxy.
Alternatively, you can extend the binding with a behavior that automatically adds the custom header prior to making each call. This is a good example: http://weblogs.asp.net/avnerk...