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);
Related
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.
I had a similar issue with this question, when updating a record using EF6.
I really thought I had cracked the whole updating thing, but now have to almost identical functions updating in what I think was an identical way. One works, the other doesn't. I have fixed the one that doesn't work by using Jamie's comment in the above question, but I'd like to understand if the function that works, really shouldn't and so is on borrowed time and I should make more like the 'fixed' one. Or, why the 'fixed' one didn't work in the first place. I even moved them into the same controller so that the database (DB) context was guaranteed the same. Have I missed something and they are not identical (functionally) at all?
It might also help some others out there that struggle with this as I did.
The function that works (cut down) is:
[HttpPost]
[Route("UpdateAddBusinessService")]
public async Task<IHttpActionResult> UpdateAddBusinessService(BusinessServiceDTO servicetoupdateoradd)
{
... pre check stuff...
try
{
if (servicetoupdateoradd.Id != null) // This is an existing service to be updated - if Is Null then create new
{
BusinessService businessService = await db.BusinessServices.FindAsync(servicetoupdateoradd.Id);
if (businessService != null)
{
Mapper.Map(servicetoupdateoradd, businessService);
db.Entry(businessService).State = EntityState.Modified;
await db.SaveChangesAsync();
return Ok("Service Updated");
}
else
The function that doesn't work is:
[HttpPost]
[Route("UpdateImage")]
public async Task<IHttpActionResult> UpdateImage(ImageDTO imageDTO)
{
... pre check stuff ...
try
{
// First find the image
// Image imagetoupdate = await db.Images.FindAsync(imageDTO.Id); <<-This FAILS.
Image imagetoupdate = db.Images.AsNoTracking().Single(x => x.Id == imageDTO.Id); <<- This WORKS
if (imagetoupdate != null)
{
imagetoupdate = Mapper.Map<ImageDTO, Image>(imageDTO); // Move the stuff over..
db.Entry(imagetoupdate).State = EntityState.Modified;
await db.SaveChangesAsync();
return Ok();
}
I wondered (as you will no doubt), if my Mapper function was doing anything, but I suspect not (without digging too deep, but I guess it could be), my Mapper.Config functions for the two DTO's are very similar:
cfg.CreateMap<Image, ImageDTO>();
cfg.CreateMap<ImageDTO, Image>();
and:
cfg.CreateMap<BusinessService, BusinessServiceDTO>();
cfg.CreateMap<BusinessServiceDTO, BusinessService>();
I would really just like to understand the 'correct' way of doing this so it doesn't bite me again. Thanks in advance.
EDIT: I was asked (quite reasonably) if the 'pre-check stuff' does anything to fetch the data, it doesn't, but there is a subtle difference, that I might have missed...
This is from the BusinessService function that works:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
string userid = User.Identity.GetUserId(); //Check user is valid
if (servicetoupdateoradd.UserId != userid)
{
var message = "User Id Not found - Contact support";
HttpResponseMessage err = new HttpResponseMessage() { StatusCode = HttpStatusCode.ExpectationFailed, ReasonPhrase = message };
return ResponseMessage(err);
}
This is from the UpdateImage function that didn't work:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
string userid = User.Identity.GetUserId();
SGGUser user = db.Users.Find(userid); // Use this find and not UserManager becuase its a different context and buggers up the file save
if (user == null)
{
var message = "User Id Not found - Contact support";
HttpResponseMessage err = new HttpResponseMessage() { StatusCode = HttpStatusCode.ExpectationFailed, ReasonPhrase = message };
return ResponseMessage(err);
}
I see that in this one, though I don't fetch the relevant data, I do use the 'db' context.. could that be it?? The Image object does contain a reference to the user, so maybe that does some magic in the background code?
Appologies, I just didn't want to clutter up the question too much...
This line:
Mapper.Map(servicetoupdateoradd, businessService);
and this line:
imagetoupdate = Mapper.Map<ImageDTO, Image>(imageDTO); // Move the stuff over..
look similar, but do two different things.
The first line will tell Automapper to copy values from the first object over to the second object reference using the mapping rules.
The second line will tell Automapper to make a completely new reference to the entity with the mapped over values from the provided object and return it.
So in the first case, the entity reference is preserved to the one the DbContext knows about. The reference was loaded from a DbContext and should be tracking changes so you shouldn't even need to set it's entity state. In the second case, Automapper is creating an entirely new reference and assigning it over top the original reference. EF is treating that as a completely new instance and trying to attach it, resulting in it complaining because the context had already loaded that entity, you just overwrote the reference.
It should work if you change the second instance to:
Mapper.Map(imageDTO, imagetoupdate);
I am not sure if the issue I am having is related to the way I'm using Task or if I am an not using ReadAsAsync correctly. I am following the pattern I found here:
http://blogs.msdn.com/b/henrikn/archive/2012/02/11/httpclient-is-here.aspx
Background:
Object I am deserializing is a POCO. Properties have no attributes. It is just a few value type properties and a couple collection properties. REST service appears to work ok also. When I look at the JSON returned by the service it appears to be OK.
Using Web API 2.1 5.1.2
Problem:
.. is calling HttpResponseMessage.Content.ReadAsAsync(). Sometimes it works (returns an object) and sometimes it doesn't (throws "Thread was being aborted" or returns null). It appears the content property can be read once only and subsequent reads throw errors. See comments in code below.
Related questions:
HttpContent.ReadAsAsync Deserialization issue
Question appears to be similar to mine. Answer indicates a bug but this is over two years old.
Code:
[TestMethod]
public void AddSiteTest()
{
// Use POST to create a resource i.e. insert. Use PUT to update.
Site site = new Site {SiteName = "Test", Active = true, URI="www.test.com" };
Site newSite = null;
client.PostAsJsonAsync<Site>(baseURI + "/Sites/AddSite?securityKey="+ SecurityKey, site).ContinueWith(x =>
{
HttpResponseMessage response = x.Result;
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
try
{
string str = Task.Run(() => response.Content.ReadAsStringAsync()).Result; // yep its json and it is a proprety serialized object
// Method 1 (preferred... ):
//Site siteA = Task.Run(() => response.Content.ReadAsAsync<Site>()).Result; // usuallly throws if content has been read
// Method 2:
Site siteB = response.Content.ReadAsAsync<Site>().Result; // usully returns a valid result (when I dont put a breakpoint on it). Does not deadlock.
// Method 3:
response.Content.ReadAsAsync<Site>().ContinueWith(d =>
{
Site siteC = d.Result; // returns null
});
}
catch (Exception ex)
{
string y = ex.Message;
}
}
});
}
try to use await:
string str = await response.Content.ReadAsStringAsync();
And you have to add async before void in your method.
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'm very new to BreezeJS and i'm doing something wrong, but not sure what. I am using a 3rd party API for my GET requests and using my own server backend to process the SaveChanges to fire off each request individually to the 3rd party as I can't customize the post/put requests to the exact syntax and post data format I need.
Our Model is dynamic (meaning customers can add new attributes/fields which then flow through from the rest api to our client) so that's why the code looks like it does below, this is the controller:
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
var context = JsonConvert.DeserializeObject<List<dynamic>>(saveBundle.SelectToken("entities").ToString());
foreach (var entity in context)
{
foreach (JProperty obj in entity)
{
if (obj != null)
{
// nothing right now but in future persist somehow
}
}
}
// Construct the save result to inform the client that the server has completed the save operation
var keyMappings = new List<KeyMapping>();
return new SaveResult()
{
Entities = context.Cast<object>().ToList(),
Errors = null,
KeyMappings = keyMappings
};
}
Call stack looks like such:
TypeError: undefined is not a function
at http://localhost:5749/Scripts/breeze.debug.js:14114:51
at http://localhost:5749/Scripts/breeze.debug.js:235:26
at Array.map (native)
at __map (http://localhost:5749/Scripts/breeze.debug.js:234:15)
at proto.visitAndMerge (http://localhost:5749/Scripts/breeze.debug.js:14111:16)
at http://localhost:5749/Scripts/breeze.debug.js:12806:48
at __using (http://localhost:5749/Scripts/breeze.debug.js:395:16)
at Object.processSavedEntities (http://localhost:5749/Scripts/breeze.debug.js:12794:13)
at saveSuccess (http://localhost:5749/Scripts/breeze.debug.js:12776:67)
at deferred.promise.then.wrappedCallback (http://localhost:5749/Scripts/angular.js:11046:81) undefined
I traced it to this line in proto.visitAndMerge (line 14114 in breeze.debug.js):
if (node.entityAspect.entityState.isDeleted()) {
If you think I'm doing something idiotic I'm all ears too. The third party API can be modified to do a GET accordingly but there is nothing to handle the SaveChanges bundle so as far as I know this is what I need to do.
Any advice would be great.
For reference, I was trying to follow this pattern: Breezejs SaveChanges: is it possible to return a custom SaveResult object, somehow?
I figured it out. entityAspect is sent along with the request. So converting it to a dynamic object created an entityAspect property which I then sent back to the client. This entityAspect needed to be removed so that it would not interfere with the JavaScript object.
Here's some code, maybe it helps someone someday:
var entities = JsonConvert.DeserializeObject<List<dynamic>>(saveBundle.SelectToken("entities").ToString());
foreach (var entity in entities)
{
JObject objEntityAspect = entity["entityAspect"];
JToken objEntityState = objEntityAspect["entityState"];
if (objEntityState.Value<string>() == "Modified")
{
// make a post with the instance id
}
entity.Remove("entityAspect");
}
entity.Remove("entityAspect") was the key component needed.