Blazor not detecting Model has updated - asp.net-core

Im currently having an issue where after I fetch data from my api, the view still seems to think the data is null. Please see below code:
View:
#if (goals == null)
{
<Loader />
}
else if (goals.Count == 0)
{
<div class="center-text">
<h2>It doesn't look like you have any goals create yet!</h2>
</div>
}
else
{
<h1>found stuff!</h1>
}
#functions {
List<GoalViewModel> goals;
protected override async Task OnInitAsync()
{
var token = await LocalStorage.GetItem<string>("AuthToken");
var httpClient = HttpClientExtensions.GetAuthHttpClient(token);
goals = await httpClient.GetJsonAsync<List<GoalViewModel>>(ClientSettings.GetHostRoot() + "/api/Goals/");
}
}
the controller action being hit looks like the following (I've verified that it is being called correctly and is returning data via the chrome network tab and fiddler):
[HttpGet]
public IActionResult Get()
{
try
{
var goalIndexDtos = _goalManager.GetAll(_claimResolver.User.FindFirstValue(ClaimTypes.NameIdentifier));
var goalViewModels = Mapper.Map<List<GoalViewModel>>(goalIndexDtos);
return Ok(goalViewModels);
}
catch (Exception ex)
{
log.Error(FormatError(nameof(GoalsController), nameof(Get), ex));
return BadRequest(ex);
}
}
My issue is that the <Loader /> always displays whereas I should be seeing a <h1>found stuff!</h1> since my controller is returning data appropriately and the blazor view code is successfully deserializing the data.
What am I missing here? I'm doing very similar things in other places in my application and they seem to work fine. I've compared this use case to the others over and over and don't see anything different.
I've even stuck a Console.WriteLine(goals.Count); line after the call to retrieve goals from the server and it correctly prints 1 to the console.
UPDATE: after playing around with everything I could think of, I deleted all data from the db table that goals is being retrieved from. this returns an empty list from my controller. In this case <h2>It doesn't look like you have any goals create yet!</h2> does print as expected! HOWEVER, the second I add a row and a list of count 1 is returned, all I get is a loader
SOLVED: After cleaning, building, rebuilding and closing/opening visual studio multiple times, my issue remained. It was only after restarting my machine that this began to work as expected.

Related

Unable to create a Role using RoleManager in Blazor Serverside

I had some code using the RoleManager that I had copied from an MVC project to create roles in a Blazor project.
It compiles okay but when I step through the code it gets to that line and then appears to throw and exception, as it doesn't ever go to the next line. I am unable to catch an exception though.
Since my code didn't work I found code on the web and it behaved the same, so I changed how it was injected and I got a different error, so I found a third way of doing it and that too gets to the line that tests to see if there is a role already existing and blows up.
Here is the latest attempt
[Inject]
IServiceProvider services {get;set;}
public async Task Initialize()
{
using (var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>())
{
string proRole = "Pro";
if (!await roleManager.RoleExistsAsync(proRole))
{
var temp = await roleManager.CreateAsync(new IdentityRole { Name = proRole });
}
}
}
And it blows up on the awaited if statement.
Here is the previous code that should work that doesn't.
string proRole = "Pro";
string proClientRole = "ProClient";
if (!await _roleManager.RoleExistsAsync(proRole))
{
var temp = await _roleManager.CreateAsync(new IdentityRole { Name = proRole });
}
which is inside of a method.
I also had it as #{code in the Razor file and after an hour of trying different things there I moved it to a base class because they have been more stable in the past.
It is not the database connection because that is well verified and also because UserManager is called in the same class and it work
I also tried this code (Blazor Role Management Add Role trough UI (Crud)) both suggestions.
This is one bad thing about Blazor for me is it is buggy I never know if it is my bad, or just something wrong with the latest greatest. But I am assuming it is my bad in this case.
Anyway any help would be much appreciated, I am way too many hours on this,
I copy/pasted the same code to the "/" page and it works there.
For some reason it wouldn't work in a component loaded into a component but the standard Role code works as expected in the "/" page.
Most likely I should have restarted my computer as it now works in the original location too.

Is it possible to have a function in a controller act as if the controller has the [ApiController] attribute but it has not?

I have a .net core MVC project that uses AJAX to retrieve data when loading grids.
Today, both the function returning the view and the function returning the data for the grid, is in the same controller. This is not optimal for many reasons. I.e. I would like a Json ProblemResult to be returned if a exception occurs when calling function using AJAX, but when returning a View, I would like the Developer Exception page to be shown if an error occurs.
I could split the functions into different Controllers and annotate one of them with the ApiController attribute, but since the project has several hundreds of controllers it would be a significant task to do so.
What I would like is this:
If context type is application/json: Do model validation and return a “ProblemResult” if a exception occurs, otherwise use the Developers Exception Page to show the error.
Can this be done in a easy way, or do I need to build a middleware and handle it all by myself?
The easy way, meaning, doing this from a function that returns either a view or a type of JSON result would look something like this:
public IActionResult AjaxOrView(CheckModel model)
{
var isAjax = Request.Headers["X-Requested-With"] == "XMLHttpRequest";
var modelStateValid = ModelState.IsValid;
if (isAjax)
{
if (!modelStateValid)
{
return JsonProblemResult();
}
return Json();
}
if (!modelStateValid)
{
// this will throw and the exception page will be shown
throw new Exception();
}
return View();
}

In Blazor dealing with unexpected results from the api web server

I'm developing a fairly simple Blazor app using a lot of default template functionality, and I can't figure out how to handle an ActionResult from the server that isn't the normal return value.
On the server side I've slightly modified the default controller template to look something like this:
public async Task<ActionResult<MyData>> GetSession(int id)
{
var myData= await FetchMyData(id);
if (myData== null)
{
return NotFound();
}
return myData;
}
That check for a null value was in the original template - it seems like a good idea so I kept it. On the client side my code looks like this:
public async Task<MyData> GetMyData(int id)
{
return await Http.GetJsonAsync<MyData>("/api/MyData/" + id);
}
It all works quite well, except the client side code doesn't handle the case where the server side returns a "NotFound()" result. It's not a show stopper, but it's driving me crazy that I don't know how to do it.
It seems that the GetJsonAsync() call on the client is silently unwrapping the return Value from the ActionResult wrapper (I guess?). Does that mean if I want to handle a NotFound condition I should be using a different httpclient function and maybe deserializing the object Value myself? If so, anyone want to volunteer an example?
Or am I missing something and there's an easier way?
It seems stupid to check for a condition on the server side just to send the client a warning that ultimately results in an unhandled exception.
I tried Henk Holterman's suggestion of just adding a try/catch, and it turns out the exception that was thrown had the information I wanted - that is the status being returned by the server. So what I should have done was this:
public async Task<MyData> GetMyData(int id)
{
try
{
return await Http.GetJsonAsync<MyData>("/api/MyData/" + id);
}
catch (System.Net.Http.HttpRequestException e)
{
.... process the exception
}
}
Turns out HttpRequestException has the HResult, which is what I was looking for.
Thanks Henk.

Persisting MVC4 controller data thru multiple post backs

I have a MVC4 controller that calls its view multiple times, each time with a different set of ViewBags. The view renders the contents of a Form based on the absence or presence of those ViewBags via something like this:
#using (Html.BeginForm())
{
#if (ViewBag.Foo1 != null)
{
#Html.DropDownList("Bar1",....
}
#if (ViewBag.Foo2 != null)
{
#Html.DropDownList("Bar2",....
}
<input name="ActionButton" type="submit" value="Ok"" />
}
Each time the user clicks the submit button, the controller checks to see what is in the collection and makes a new set of ViewBags before calling the view again, sort of like this:
public ActionResult Create()
{
ViewBag.Foo1 = "blawblaw";
return View();
}
[HttpPost]
public ActionResult Create(FormCollection collection)
{
if (collection["Bar1"] != null)
{
string FirstPass = collection["Bar1"];
ViewBag.Foo2 = "blawblaw";
}
if (collection["Bar2"] != null)
{
string SecondPass = collection["Bar2"];
ViewBag.Foo3 = "blawblaw";
}
return View();
}
What I need to do now is somehow have each pass thu the controller 'remember' something about its previous passes. That is, in my example, the second pass thru the controller (the one where collection["Bar2"] is true), the value of FirstPass is null.
How can I do that?
In that case have a look at best practices for implementing a wizard in MVC. Some good suggestions here. Personally I would still consider using separate and distinct urls. Also, If you have db access in your solution you can still store temporary data before updating the main model. Think about what you want to happen if the user doesn't complete the whole journey the first time round...

Silverlight + WCF Data Services getting InvalidOperationException :The context is already tracking a different entity with the same resource Uri

I'm trying to replace an object with a new one and am getting the mentioned exception. I've tried several combination and can't get around it.
I have a Playlist that has Items (the Items has another nested object, but I'm leaving it out to help make my question clearer. The user can change which items are in the playlist.
if (playlistChanged)
{
// remove selectedForRemoval
IEnumerable<PlaylistItemViewModel> nonSelectedItems = selectedDisplayTemplates.Where(pivm => pivm.IsSelectedForRemoval);
foreach (temViewModel ivm in nonSelectedItems)
{
context.DeleteObject(ivm.Model);
}
// clear out and remove old items
foreach (Item item in playlist.PlaylistItems)
{
context.DeleteObject(item);
}
playlist.PlaylistItems.Clear();
// add the selectedItem(s) to the playlist
// these items can be from the Media, or other tables
// so are newly created in code on the client
foreach (ItemViewModel ivm in selectedItems)
{
playlist.Items.Add(ivm.PlaylistItemModel);
context.AddToItems(ivm.PlaylistItemModel);
}
context.BeginSaveChanges(SaveChangesOptions.Batch, new AsyncCallback((iar) =>
{
try
{
// Callback method for the async request, retrieves the status of the requested action
DataServiceResponse response = context.EndSaveChanges(iar);
}
catch (DataServiceRequestException)
{
throw;
}
}), context);
}
Any help is appreciated.
EDIT: I was overriding the Equals and ToString in Playlist partial class. After I removed those, it started working.
I was overriding the Equals and ToString in Playlist partial classes in Silverlight. After I removed those, it started working. I'm going to avoid that from now on with WCF Data Services.
If you fetched the data using a different context from the one you are trying to add/delete with, you will get the exception you posted. Either dispose of the original context you fetched the data with or explicitly call Detach on the item you are calling AddItem/DeleteObject on.