Problem with Html.Action call to action with [HttpGet] attribute - error-handling

I have just encountered a strange problem. I have fixed it, but I am hoping that you may be able to help me better understand what actually went wrong. I'll start with an explanation of what happened. The problem concerns a simple MVC3 RC1 app.
In my app's master page there is a call to an action on a controller to render a login-form:
#Html.Action("LoginForm", "Account")
The action method on the AccountController class returns a PartialViewResult containing the login-form.
public PartialViewResult LoginForm()
{
return PartialView();
}
Today I made a change to this action method and attributed it with the HttpGetAttribute like so:
[HttpGet]
public PartialViewResult LoginForm()
{
return PartialView();
}
This is what caused problems. However, the problems only existed in one particular scenario - and this is what baffles me. When posting a form to a controller everything would work just fine provided that the controller action then returned a RedirectToRouteResult. If the action just returned a ViewResult (to its default view), my Http404 error handling would kick in and loop forever.
I have implemented 404 error handling in a manner very similar to what is described in the third answer to this question: Requirements for 404. If you don't want to read that post, in simple terms I override the HandleUnknownAction method on my base controller class, and in that method I instantiate an instance of my ErrorController class and call Execute on it, passing it an instance of RouteData:
protected override void HandleUnknownAction(string actionName)
{
// If controller is ErrorController dont 'nest' exceptions
if (this.GetType() != typeof(ErrorController))
this.InvokeHttp404(HttpContext);
}
public ActionResult InvokeHttp404(HttpContextBase httpContext)
{
IController errorController = DependencyResolver.Current.GetService<ErrorController>();
var errorRoute = new RouteData();
errorRoute.Values.Add("controller", "Error");
errorRoute.Values.Add("action", "Http404");
errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
errorController.Execute(new RequestContext(httpContext, errorRoute));
return new EmptyResult();
}
All the ErrorController does is log the error and return a view with a friendly error message. Well, that's how it should work. But in this case the error handling would enter into an infinite loop where the AccountController (to which my form was posted) would invoke the HandleUnknownAction over and over and over again.
There was nothing in the error logs to indicate what had gone wrong (I think I log just about everything) - which was also strange. So I figured that if removed the HandleUnknownAction method from my controller base class maybe something else would be revealed. And it was:
2010-12-10 19:11:47,956 [4] ERROR Infrastructure.Log4NetAuditor [System.Web.HttpException (0x80004005): Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'. ---> System.Web.HttpException (0x80004005): Execution of the child request failed. Please examine the InnerException for more information. ---> System.Web.HttpException (0x80004005): A public action method 'LoginForm' was not found on controller 'Cdo.Web.Controllers.AccountController'.
What the? When I saw this I remembered that I'd put the HttpGetAttribute on this method - so I promptly removed it... and order was restored. I am happy to have discovered what caused this - but I remain in the dark on why it happened. If you are able to help me shed some light on this I'd be much obliged. Why would the HttpGetAttribute make a difference here?

try setting outputcache attribute to action. I remember that kind of problem and this was a solution. set duration on 1
[OutputCache(Duration = 1, VaryByParam = "None")]

Related

Blazor exception - The current thread is not associated with the Dispatcher. Use InvokeAsync()

I my Blazor application I have such exception
System.InvalidOperationException: The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.
at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg)
at Microsoft.AspNetCore.Components.EventCallback`1.InvokeAsync(TValue arg)
at MyApplication.Web.Shared.Application.ApplicationBarService.SearchFromUri(NavigationManager navigationManager) in /app/src/MyApplication.Web/Shared/Application/ApplicationBarService.cs:line 132
at MyApplication.Web.Shared.Application.ApplicationBar.OnAfterRenderAsync(Boolean firstRender) in /app/src/MyApplication.Web/Shared/Application/ApplicationBar.razor:line 367
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
2020-09-01 10:32:06.818 +00:00 [ERR] Unhandled exception in circuit 'b625BJVxR9Sa5e1W6l6unK0G7RAkkLuM3kbvMggpJV0'.
System.InvalidOperationException: The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.
at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg)
at Microsoft.AspNetCore.Components.EventCallback`1.InvokeAsync(TValue arg)
at MyApplication.Web.Shared.Application.ApplicationBarService.SearchFromUri(NavigationManager navigationManager) in /app/src/MyApplication.Web/Shared/Application/ApplicationBarService.cs:line 132
at MyApplication.Web.Shared.Application.ApplicationBar.OnAfterRenderAsync(Boolean firstRender) in /app/src/MyApplication.Web/Shared/Application/ApplicationBar.razor:line 367
It asks to use InvokeAsync, but I'm already into an "OnAfterRenderAsync"!
So, why do I have such an issue?
In my situation, I have 3 elements
an ApplicationBarService (global to the app)
an ApplicationBarComponent.razor
a page Index.razor
What I suspect
The ApplicationBar component is inside the page Index.razor. It means that OnAfterRender is called on ApplicationBar first, then on Index.
So, here is the call stack / order:
ApplicationBar.OnAfterRenderAsync ->
ApplicationBarService.SearchFromUri -> (CALL DONE WITH AN EventCallback)
Index.Search(...)
One problem is that Index.razor is not yet "ready" (no call to OnAfterRender has been done yet). There I cannot do any JS call :-(
Maybe I should do this call once all "parent" are ready, but how ?
Some code
It is a simple event
public EventCallback<SearchEventArgs> OnSearch;
I call it this way:
await OnSearch.InvokeAsync(args);
And the last code, On Index.razor I have:
public async Task Search(SearchArgs args)
{
base.InvokeAsync( ... );
}
The last method is the one called by the event, there I also use base.InvokeAsync to insure I do the call in the right thread ! But even with this I have some issues, I cannot do JS calls because the OnAfterRender has not been called yet !
So, do you have any idea about the problem?
Also, I have to some change, just to be sure to call from the same components.
If you look at the code:
I call from OnAfterRender, call a "static" class, then go back to the same component. Then this component try to do the last call.
In the last call I use InvokeAsync and EventCallback (This one should InvokeAsync too)
But even with this, it ask me to call InvokeAsync (But it is done) !!!
Without seeing all the code its hard to say for sure, but likely you need to surround a StateHasChanged like
InvokeAsync(() => StateHasChanged());
Blazor university has a nice in-depth explanation.

Generic Mediatr Handler not found

I'm trying to register a generic request handler for a generic request, but I'm getting the error below when calling
await _mediator.Send(new ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>());
System.InvalidOperationException: Handler was not found for request of
type
MediatR.IRequestHandler`2[MyNamespace.ExchangeOrderRequest`1[MyNamespace.ExchangeOrderResponseSuccessEvent],MediatR.Unit]`.
Register your handlers with the container. See the samples in GitHub
for examples.
As side note, for giggles, I was able to inject an instance of IRequestHandler<ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>> into a controller just fine.
// Some assembly scanning, doesn't find my handler
services.AddMediatR(typeof(Startup), typeof(ExchangeOrderRequest), typeof(IDocumentMessage), typeof(OrderExecution.Handler));
// Try to manually add the handler. Still doesn't find it
services.AddTransient<IRequestHandler<ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>>, ExchargeOrderRequestHandler<ExchangeOrderResponseSuccessEvent, ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>>>();
public class ExchargeOrderRequestHandler<TEvent, TRequest> : IRequestHandler<TRequest>
where TRequest : ExchangeOrderRequest<TEvent>
where TEvent : ExchangeOrderEvent
{
// Stuff
}`
public class ExchangeOrderRequest<T>: DocumentMessage, IRequest where T: ExchangeOrderEvent
{
// Stuff
}
public class ExchangeOrderEvent : IEvent
{
// Stuff
}
What am I missing here?
I'm having the same issue...
However, I am able to register the handler like this..
services.AddTransient(typeof(IRequestHandler<,>), typeof(CustomHandler<,>));
This works for only one generic handler... I have many... I need to be able to do something like this:
services.AddTransient(typeof(IRequestHandler<,>), typeof(CustomHandler1<,>));
services.AddTransient(typeof(IRequestHandler<,>), typeof(CustomHandler2<,>));
//etc...
When I try and do this... no matter what command I send to MediatR it resolves the last handler I registered.. So naturally the type constraints are violoated and a runtime exception occurs.

Proper way to send Web API response

I read somewhere that TRY CATCH is not recommended in Web API methods.
I'm making the following call into a method and if all goes well, I want to return an Employee object along with Status 200 but if something goes wrong e.g. database call fails, etc. I want to return status 500. What's the right way to handle that code?
[HttpPost]
public async Task<IHttpActionResult> PostNewEmployeeAsync(Employee emp)
{
var newEmployee = await RegisterEmployee(emp);
return Ok(emp);
// What if I had a database error in RegisterEmployee method. How do I detect the error and send InternalServerError()
}
private async Task<Employee> RegisterEmployee(Employee emp)
{
// Call DB to register new employee, then return Employee object
}
Your code should return the error code that matches the case that you have, for example if your code couldn't find the required resource in the database return NotFound,
but if you code raises an exception, avoid wrapping your code by try/catch block and instead the exception should bubble up to the level that you can handle it globally, to do this you have many options like :
1- Implement an ExceptionFilter where you can handle all the unhandled exceptions raised in your controllers (this doesn't include any exception happens before the controllers in the pipeline).
See this for more details about ExceptionFilterAttribute.
2- If you are using Web API 2, you can implement the interface IExceptionHandler where you can handle all the exception happens anywhere in the pipeline and there you can return the errors you want.
See this for more details about Global Exception Handling in Web API 2.
Hope that helps.
You don't want to avoid try/catch entirely, you just need to be really careful about it. Wrap your code in a try block, and catch the exception you're expecting. Inside the catch, return the error response.

Flow of initializing objects in XAML?

I'm not sure but from my hours of debugging, this should be the best description of my problem I can give.
I'm creating a WinRT app, there are two pages- Main Page and Details Page. Inside Main Page constructor, I have initialized a listbox. On click of any of the element of listbox, user is taken to the Details page.
I'm just learning all this and design may not be best but here is what I did.
I took a static variable in MainPage.cs, and set it to point to the element which is clicked by the user. Now in the constructor of the Details page, I used this static variable to set the datacontext of Details Page itself.
What flow I'm expecting is:-
MainPage is created first. Listbox is setup.
User will click on any of the element of listbox. Itemclick event handler runs. It will set the static variable (of Mainpage.cs) to hold the infomation which item is clicked and navigate user to the Details page.
In Details page constructor, I have set the datacontext to point to some information based on the value of static variable mentioned in the previous step.
It works for most of the times, but once in like every 5 times, The Details page constructor throws an exception stating the static variable is not initialized yet. Why is Details page's constructor running when I'm starting the app? and why only sometimes? Do I need to set DataContext of Details Page in some other method instead of constructor?
The code is somewhat complex and too much in terms of domain of the problem so I'm avoiding posting it. But if I'm failing to explain the problem please tell, I'll post it keeping it as related as I can.
CODE:-
This is the method called when an item in listbox is clicked--will take user to the Details page.
private void overviewlistbox_Tapped_1(object sender, TappedRoutedEventArgs e)
{
MatchOverview selectedmatch = (sender as ListBox).SelectedItem as MatchOverview;
matchFullDetails = new ObservableCollection<Match>();
foreach (Match m in UpdateController.matchList)
{
if (m.matchDescription == selectedmatch.matchDesc)
{
matchFullDetails.Add(m);
break;
}
}
if(!(matchFullDetails.Count == 0))
this.Frame.Navigate(typeof(Details));
}
This is the constructor for Main Page:-
public static ObservableCollection<Match> matchFullDetails;
public MainPage()
{
matchFullDetails = new ObservableCollection<Match>();
this.InitializeComponent();
UpdateController update = new UpdateController(); // Creating new object will update the overview_list of UpdateController(static list).
overviewlistbox.ItemsSource = UpdateController.overview_list;
}
And this is the code for constructor of details page, where the exception occurs:-
public static ObservableCollection<Match> matchdetails = new ObservableCollection<Match>();
DispatcherTimer dtm_detailspage = null;
public Details()
{
this.InitializeComponent();
matchdetails = MainPage.matchFullDetails; // matchdetails.Last<>() is take because we only need item which is added latest to the collection.
if (matchdetails.Last<Match>().type == "TEST") // Exception is thrown here--Initialization
// error. When I check MainPage.matchFullDetails,
// no data is shown which means its not yet
// initialized. Also the exception is thrown either at
// the start of the app, or when details page is visited. That too once in 4-5 times, not always.
{
matchdetails.Add(matchdetails.First<Match>() as TestMatch);
}
if (matchdetails.Last<Match>().type == "ODI")
{
matchdetails.Add(matchdetails.Last<Match>() as ODIMatch);
}
if (matchdetails.Last<Match>().type == "T20")
{
matchdetails.Add(matchdetails.Last<Match>() as T20Match);
}
}
Exception Screenshot:-
Call Stack data on bug encounter:-
[Cricket Expert.exe!Cricket_Expert.Details.Details() Line 33 + 0x5 bytes
[External Code]
Cricket Expert.exe!Cricket_Expert.Common.SuspensionManager.RestoreFrameNavigationState(Windows.UI.Xaml.Controls.Frame frame) Line 236 + 0x5 bytes
Cricket Expert.exe!Cricket_Expert.Common.SuspensionManager.RestoreAsyn() Line 124 0x8 bytes
Cricket Expert.exe!Cricket_Expert.App.OnLaunched(Windows.ApplicationModel.Activation.LaunchActivatedEventArgs args) Line 74 + 0x5 bytes
[External Code]
MAJOR UPDATE:
I finally found the flaw. If the Details page is still active, and the app is restarted, the problem occurs.
Is there a solution to this problem??
You can pass information on what needs to be displayed on the Details page through the Navigate call and set the DataContext in OnNavigatedTo override to avoid using static variables. Pages don't get created unless you do it specifically e.g. by navigating to one. They might not be recreated if a page has NavigationCacheMode changed from the default (Disabled) so instances of the page can be reused during navigation calls. Ultimately it's hard to say what's wrong but it seems like something in your code and we couldn't help you if you don't share a sample that reproduces the problem.
*EDIT
One way to debug Details being created before MainPage would be to add this code at the beginning of the Details constructor:
if (MainPage.matchFullDetails == null)
{
System.Diagnostics.Debugger.Break();
}
Then look at the Call Stack panel in Visual Studio to see how it gets constructed.
One way to see if matchFullDetails is ever set to null is to search for its assignment (put a cursor on matchFullDetails in Visual Studio code editor and hit Shift+F12).
Another way would be to make matchFullDetails into a property and test it like this:
private static ObservableCollection<Match> _matchFullDetails;
public static ObservableCollection<Match> matchFullDetails
{
get
{
return _matchFullDetails;
}
set
{
if (value == null)
{
System.Diagnostics.Debugger.Break();
}
_matchFullDetails = value;
}
}
*EDIT 2
You can initialize your static property in a static constructor like this:
public static ObservableCollection<Match> matchFullDetails;
static MainPage()
{
matchFullDetails = new ObservableCollection<Match>();
}
public MainPage()
{
this.InitializeComponent();
UpdateController update = new UpdateController(); // Creating new object will update the overview_list of UpdateController(static list).
overviewlistbox.ItemsSource = UpdateController.overview_list;
}
this will prevent the null reference exception but won't fix your problem overall. When your app gets suspended and resumed - you have to restore the full state and it seems like your matchFullDetails collection would need to be serialized and saved to disk when your app gets suspended. Alternatively you might simply ignore the suspension manager call in App.xaml.cs and always start on home page, though that's not a very good experience and I am not sure if it satisfies app certification.

Metro c++ async programming and UI updating. My technique?

The problem: I'm crashing when I want to render my incoming data which was retrieved asynchronously.
The app starts and displays some dialog boxes using XAML. Once the user fills in their data and clicks the login button, the XAML class has in instance of a worker class that does the HTTP stuff for me (asynchronously using IXMLHTTPRequest2). When the app has successfully logged in to the web server, my .then() block fires and I make a callback to my main xaml class to do some rendering of the assets.
I am always getting crashes in the delegate though (the main XAML class), which leads me to believe that I cannot use this approach (pure virtual class and callbacks) to update my UI. I think I am inadvertently trying to do something illegal from an incorrect thread which is a byproduct of the async calls.
Is there a better or different way that I should be notifying the main XAML class that it is time for it to update it's UI? I am coming from an iOS world where I could use NotificationCenter.
Now, I saw that Microsoft has it's own Delegate type of thing here: http://msdn.microsoft.com/en-us/library/windows/apps/hh755798.aspx
Do you think that if I used this approach instead of my own callbacks that it would no longer crash?
Let me know if you need more clarification or what not.
Here is the jist of the code:
public interface class ISmileServiceEvents
{
public: // required methods
virtual void UpdateUI(bool isValid) abstract;
};
// In main XAML.cpp which inherits from an ISmileServiceEvents
void buttonClick(...){
_myUser->LoginAndGetAssets(txtEmail->Text, txtPass->Password);
}
void UpdateUI(String^ data) // implements ISmileServiceEvents
{
// This is where I would render my assets if I could.
// Cannot legally do much here. Always crashes.
// Follow the rest of the code to get here.
}
// In MyUser.cpp
void LoginAndGetAssets(String^ email, String^ password){
Uri^ uri = ref new URI(MY_SERVER + "login.json");
String^ inJSON = "some json input data here"; // serialized email and password with other data
// make the HTTP request to login, then notify XAML that it has data to render.
_myService->HTTPPostAsync(uri, json).then([](String^ outputJson){
String^ assets = MyParser::Parse(outputJSON);
// The Login has returned and we have our json output data
if(_delegate)
{
_delegate->UpdateUI(assets);
}
});
}
// In MyService.cpp
task<String^> MyService::HTTPPostAsync(Uri^ uri, String^ json)
{
return _httpRequest.PostAsync(uri,
json->Data(),
_cancellationTokenSource.get_token()).then([this](task<std::wstring> response)
{
try
{
if(_httpRequest.GetStatusCode() != 200) SM_LOG_WARNING("Status code=", _httpRequest.GetStatusCode());
String^ j = ref new String(response.get().c_str());
return j;
}
catch (Exception^ ex) .......;
return ref new String(L"");
}, task_continuation_context::use_current());
}
Edit: BTW, the error I get when I go to update the UI is:
"An invalid parameter was passed to a function that considers invalid parameters fatal."
In this case I am just trying to execute in my callback is
txtBox->Text = data;
It appears you are updating the UI thread from the wrong context. You can use task_continuation_context::use_arbitrary() to allow you to update the UI. See the "Controlling the Execution Thread" example in this document (the discussion of marshaling is at the bottom).
So, it turns out that when you have a continuation, if you don't specify a context after the lambda function, that it defaults to use_arbitrary(). This is in contradiction to what I learned in an MS video.
However by adding use_currrent() to all of the .then blocks that have anything to do with the GUI, my error goes away and everything is able to render properly.
My GUI calls a service which generates some tasks and then calls to an HTTP class that does asynchronous stuff too. Way back in the HTTP classes I use use_arbitrary() so that it can run on secondary threads. This works fine. Just be sure to use use_current() on anything that has to do with the GUI.
Now that you have my answer, if you look at the original code you will see that it already contains use_current(). This is true, but I left out a wrapping function for simplicity of the example. That is where I needed to add use_current().