IFeatureCollection is disposed Object name: Collection in a Task? - asp.net-core

I want to run a Task to save the logs into a database table.
But it seems like that the HttpContext is disposedin the other thread.
Here is my code:
_ = Task.Run(() =>
{
using (var db = LogContext())
{
var request = new LoginLog
{
Url = context.HttpContext.Request.Path,
UserAgent = context.HttpContext?.Request?.Headers?[HeaderNames.UserAgent].ToString()
};
await db.AddAsync(request);
db.SaveChanges();
}
});
Here is the exception trackInfo:
at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.ThrowContextDisposed()
at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.Fetch[TFeature, TState](TFeature & cached, TState state, Func`2 factory)
at Microsoft.AspNetCore.Http.DefaultHttpRequest.get_Path()
at PowerMan.Applet.Api.Infrastructure.Filters.RequestFilter.<> c__DisplayClass4_0.< OnActionExecutionAsync > b__1() in / Users / zhaojing / Projects / PowerMan.Api / PowerMan / PowerMan.Applet / PowerMan.Applet.Api / Infrastructure / Filters / RequestFilter.cs:line 112
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.<> c.<.cctor > b__274_0(Object obj)
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
Is it the Task which make the exceptions?

Most definitely the context is disposed after the request completes.
So you will need to capture the values you will need before starting the background operation:
var url = context.HttpContext.Request.Path;
var userAgent = context.HttpContext?.Request?.Headers?[HeaderNames.UserAgent].ToString();
_ = Task.Run(() =>
{
using (var db =LogContext())
{
var request = new LoginLog
{
Url = url,
UserAgent = userAgent
};
await db.AddAsync(request);
db.SaveChanges();
}
});

Related

Error reading JToken from JsonReader in ASP.NET CORE 3.1 WebApi

I'm using Cloudinary to upload the images in my ASP.NET CORE 3.1 application and when I call _cloudinary.Upload(uploadParams), it throws an exception as following:
System.Exception: Failed to deserialize response with status code: Redirect --->
Newtonsoft.Json.JsonReaderException: Error reading JToken from JsonReader. Path '', line 0, position 0.
at Newtonsoft.Json.Linq.JToken.ReadFrom(JsonReader reader, JsonLoadSettings settings)
at Newtonsoft.Json.Linq.JToken
.Parse(String json, JsonLoadSettings settings) at Newtonsoft.Json.Linq.JToken.Parse(String json)
at CloudinaryDotNet.ApiShared.CreateResultFromString[T](String s, HttpStatusCode statusCode)
--- End of inner exception stack trace
Following is the code of my controller:
[HttpPost]
public async Task<IActionResult> AddPhotoForUser(int userId, [FromForm]PhotoForCreationDto photoForCreationDto)
{
if (userId != int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value))
{
return Unauthorized();
}
var userFromRepo = await _repo.GetUser(userId);
var file = photoForCreationDto.File;
var uploadResult = new ImageUploadResult();
if (file.Length > 0)
{
using(var stream = file.OpenReadStream())
{
var uploadParams = new ImageUploadParams()
{
File = new FileDescription(file.Name, stream),
Transformation = new Transformation().Width(500).Height(500).Crop("fill").Gravity("face")
};
uploadResult = _cloudinary.Upload(uploadParams);
}
}
photoForCreationDto.Url = uploadResult.Uri.ToString();
photoForCreationDto.PublicId = uploadResult.PublicId;
var photo = _mapper.Map<Photo>(photoForCreationDto);
if (!userFromRepo.Photos.Any(u => u.IsMain))
{
photo.IsMain = true;
}
userFromRepo.Photos.Add(photo);
if (await _repo.SaveAll())
{
var photoToReturn = _mapper.Map<PhotoForReturnDto>(photo);
return CreatedAtRoute("GetPhoto", new { userId = userId, id = photo.Id }, photoToReturn);
}
return BadRequest("Could not add the photo");
}
I have similar issue, but the error is Foribidden, only happens when i run the app from the cli, in the debugger everything goes fine.
https://github.com/cloudinary/CloudinaryDotNet/issues/223

how to assign valueprovider to controller from Model object

I have an Edit Post action method in my MVC4 application and I am trying to unit test this action. But, the Unit test fails with "NullReferenceException". Below is the unit test FYR.
[TestMethod]
public void EditAction_Should_Redirect_When_Update_Successful()
{
// Arrange
var mockHttpContext = new Mock<HttpContextBase>();
var mockRequest = new Mock<HttpRequestBase>();
mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);
// tell the mock to return "POST" when HttpMethod is called
mockRequest.Setup(x => x.HttpMethod).Returns("POST");
mockRequest.SetupGet(req => req.Form).Returns(new FormCollection());
var controller = GetTheController();
var id = 1;
// assign the fake context
var context = new ControllerContext(mockHttpContext.Object,
new RouteData(),
controller);
controller.ControllerContext = context;
var formValues = new MyModel() {
Id = 1,
ActivityDescription = "This is another description",
CreatedDate", Convert.ToDateTime("31-12-2014"),
UserId = 1,
IsCompleted = false
};
// Act
var result = controller.Edit(id, formValues) as RedirectToRouteResult;
// Assert
Assert.AreEqual("List", result.RouteValues["Action"]);
Assert.AreEqual(id, result.RouteValues["id"]);
}
Edit action method is below -
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MyModel item)
{
var viewResult = ValidateItem(item);
if (viewResult != null)
return viewResult;
//Unit test is failing at this step.
TryUpdateModel(item);
if (ModelState.IsValid)
{
_itemsRepository.Edit(item);
return RedirectToAction("Index");
}
else return View(item);
}
Below is the stacktrace for reference -
Test Outcome: Failed
Test Duration: 0:00:00.3306816
Result Message:
Test method MvcToDoListItemsDemo.Tests.TodoControllerTest.EditAction_Should_Redirect_When_Update_Successful threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
Result StackTrace:
at Microsoft.Web.Infrastructure.DynamicValidationHelper.DynamicValidationShim.IsValidationEnabled(HttpContext context)
at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.IsValidationEnabled(HttpContext context)
at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(HttpContext context, Func`1& formGetter, Func`1& queryStringGetter)
at System.Web.Helpers.Validation.Unvalidated(HttpRequest request)
at System.Web.Mvc.FormValueProviderFactory.<.ctor>b__0(ControllerContext cc)
at System.Web.Mvc.FormValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ValueProviderFactoryCollection.<>c__DisplayClassc.<GetValueProvider>b__7(ValueProviderFactory factory)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ControllerBase.get_ValueProvider()
at System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel model)
Could someone please advise if I am doing anything wrong here ?
Regards,
Ram
TryUpdateModel(item) gets the updated values for item from the controller's default ValueProvider, usually a System.Web.Mvc.FormValueProvider, which in turn parses them from the current POST request body. In unit tests, you can wrap the model in a DictionaryValueProvider<object> and return it as-is, like this:
var controller = GetTheController();
var requestModel = new MyModel()
{
/* .. values .. */
};
controller.ValueProvider = new DictionaryValueProvider<object>(
new Dictionary<string, object>() { { "MyModel", requestModel } }, null);
var result = controller.Edit(id) as RedirectToRouteResult;

Saving data in windows phone received from WCF/web service .

Saving data in windows phone received from WCF/web service .
The response may be received after sometime so how to handle this situation.
Saving data is no problem but How to handel if data is received late
You can use this code (show the code from my project):
public void sendPost(string postData, Action<MyResponse, Exception> callback, CreateResponse creater)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(UrlRequest);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Accept = "application/json";
webRequest.AllowAutoRedirect = true;
webRequest.BeginGetRequestStream(new AsyncCallback(getRequestStreamCallback), new Request()
{
HttpRequest = webRequest,
PostData = postData,
Url = UrlRequest,
CallBack = callback,
Creater = creater
});
}
private void getRequestStreamCallback(IAsyncResult asynchronousResult)
{
var request = (Request)asynchronousResult.AsyncState;
// End the stream request operation
Stream postStream = request.HttpRequest.EndGetRequestStream(asynchronousResult);
byte[] byteArray = Encoding.UTF8.GetBytes(request.PostData);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
request.HttpRequest.BeginGetResponse(new AsyncCallback(getResponseCallback), request);
}
private void getResponseCallback(IAsyncResult asynchronousResult)
{
var request = (Request)asynchronousResult.AsyncState;
try
{
HttpWebResponse response;
// End the get response operation
response = (HttpWebResponse)request.HttpRequest.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
var myResponse = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
MyResponse response_obj = request.Creater.CreateResponseObj();
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(myResponse)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(response_obj.GetType());
response_obj = (GYResponse)serializer.ReadObject(stream);
if (request.CallBack != null)
{
request.CallBack.Invoke(response_obj, null);
}
}
}
catch (WebException e)
{
if (request.CallBack != null)
{
request.CallBack.Invoke(null, e);
}
}
}
public void getInfo(string uid, Action<MyResponse, Exception> callback)
{
CreateResponse creater = new CreateResponseGetInfo();
string model = "User";
string method = "getInfo";
Params parametrs = new Params();
parametrs.Uid = uid;
//create yor request
string request = getRequestString(model, method, parametrs, Atoken);
sendPost(request, callback, creater);
}
So, you call method, which send request to web service postRequester.getInfo(uid, ResponseHandler) and use delegate for processing result.
private void ResponseHandler(MyResponse result, Exception error)
{
if (error != null)
{
string err = error.Message;
return;
}
else
{
var infoResponse = result as ResponseGetInfo;
if (infoResponse != null)
{
//result processing..
}
}
}
All the web requests you make in a Windows Phone app are Asynchronous. That means, you make a web request from your app and attach a handler to handle the response when it comes. In the response handler, you will have to take care of the response and do whatever you want with it.
Check this link Using WebClient and HttpWebRequest

Why return 500 error while calling another controller using WebClient?

I'm testing example on this link: http://msdn.microsoft.com/en-us/vs11trainingcourse_aspnetmvc4_topic5#_Toc319061802 but I have 500 error calling another controller using WebClient.
When I access to "http://localhost:2323/photo/gallery directly is running, but I'm trying from action using WebClient it return 500 error? Why?"
public ActionResult Index()
{
WebClient client = new WebClient();
var response = client.DownloadString(Url.Action("gallery", "photo", null, Request.Url.Scheme));
var jss = new JavaScriptSerializer();
var result = jss.Deserialize<List<Photo>>(response);
return View(result);
}
500 error created by below exception:
[ArgumentNullException: Value cannot be null.
Parameter name: input]
System.Text.RegularExpressions.Regex.Match(String input) +6411438
Microsoft.VisualStudio.Web.Runtime.Tracing.UserAgentUtilities.GetEurekaVersion(String userAgent) +79
Microsoft.VisualStudio.Web.Runtime.Tracing.UserAgentUtilities.IsRequestFromEureka(String userAgent) +36
Microsoft.VisualStudio.Web.Runtime.Tracing.SelectionMappingExecutionListenerModule.OnBeginRequest(Object sender, EventArgs e) +181
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
It's hard to tell. Maybe the controller action that you are calling requires authorization? Or uses session? When you send your WebClient request it doesn't delegate any of the client cookies that were sent by the client to the Index action.
Here's how you can debug your code and see the exact response returned by the server:
WebClient client = new WebClient();
try
{
var response = client.DownloadString(Url.Action("gallery", "photo", null, Request.Url.Scheme));
}
catch (WebException ex)
{
using (var reader = new StreamReader(ex.Response.GetResponseStream()))
{
string responseText = reader.ReadToEnd(); // <-- Look here to get more details about the error
}
}
And if it turns out that the problem is related to the ASP.NET Session that your target controller action depends upon, here's how you could delegate the client cookies with the request:
WebClient client = new WebClient();
client.Headers[HttpRequestHeader.Cookie] = Request.Headers["Cookie"];
error occurred because of the User-Agent Header
Resolution is:
public ActionResult Index()
{
WebClient client = new WebClient();
client.Headers[HttpRequestHeader.UserAgent] = Request.Headers["User-Agent"];
var response = client.DownloadString(Url.Action("gallery", "photo", null, Request.Url.Scheme));
var jss = new JavaScriptSerializer();
var result = jss.Deserialize<List<Photo>>(response);
return View(result);
}

Conversion to Parallel/TPL for this Async code

I'm wondering as to how I'd go aroung converting this Begin-End-Async approach to the newer TPL syntax:
public override IAsyncResult BeginRegisterClaimant(ClaimantSex claimantSex, AgeGroup ageGroup, AsyncCallback callback, object state)
{
AsyncResult<string> asyncResult = new AsyncResult<string>(callback, state);
InitManagementProxy();
m_management.RegisterClaimantCompleted += RegisterClaimantCallbackInternal;
m_management.RegisterClaimantAsync(m_configurationID, (PowWow.Service.ClaimantSex)claimantSex, (PowWow.Service.AgeGroup)ageGroup, new object[]
{ this, asyncResult
});
return asyncResult;
}
public override string EndRegisterClaimant(IAsyncResult asyncResult)
{
if (!(asyncResult is AsyncResult<string>))
{
throw new Exception("Invalid IAsyncResult object");
}
return ((AsyncResult<string>)asyncResult).Close();
}
private void InitManagementProxy()
{
WSHttpBinding binding;
if (m_management != null)
{
return;
}
binding = new WSHttpBinding(SecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
m_management = new PowWow.Service.VerifierContractClient(binding, new EndpointAddress(m_managementUri));
m_management.ClientCredentials.UserName.UserName = m_userName;
m_management.ClientCredentials.UserName.Password = m_password;
}
private static void RegisterClaimantCallbackInternal(object senderObject, PowWow.Service.RegisterClaimantCompletedEventArgs eventArgs)
{
PowWowVerifier powWowVerifier = (PowWowVerifier)((Object[])eventArgs.UserState)[0];
powWowVerifier.m_management.RegisterClaimantCompleted -= RegisterClaimantCallbackInternal;
powWowVerifier.m_management.Close();
powWowVerifier.m_management = null;
if (eventArgs.Error != null)
{
((AsyncResult<string>)((Object[])eventArgs.UserState)[1]).OnException(eventArgs.Error);
}
else
{
((AsyncResult<string>)((Object[])eventArgs.UserState)[1]).OnExecuted(eventArgs.Result);
}
}
Thanks!
EDIT
ATM, cancellation is not required. Progress reporting maybe required but not a priority.
The simplest way would be to wrap your existing code in a TaskCompletionSource and return it's Task - this will then fit in with the new async/await model coming in C# 5