how do i reload my form with its values if any exceptions are thrown in the controller for it?
i know you can use return View() but the thing is that my form is not its own page, so i am kind of stuck on how to do this. the form is a hidden modal window that is accessible from any page, as it is in the header.
70 Replies
Essentially you want to retain the form state if there were any exceptions?
yes but i also want to tell the user what the exception is
like for example, if they entered a bad title
i dont kno whwo i would do that
Then you need to send the data back after it's submitted to the server
The flow right now is
form data View without the submitted data
Html form ---------> server (server encounters error) ---------------------------------------> client
You need to change it to
form data View with the submitted data
Html form ---------> server (server encounters error) ---------------------------------------> client
You just need to supply the data in your Model
You should also use the validation API in ASP.NET
https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/validation?view=aspnetcore-8.0&tabs=visual-studio
Part 8, add validation
Part 8 of tutorial series on Razor Pages.
ok i didnt do validations yet. when i said i wanted exceptions, i actually meant that i wanted to do something like
if the amount of polls int he database is > 25 then throw an exception
and then let the user see it
Yeah, you should avoid exception for something like that
Exceptions should be used when something "exceptional" happened that shouldn't have happened or used.
Instead return an error message
if (_context.Polls.Count() >= 25)
return "No more polls can be created"; i dont think taht i can do this, because the controller is ActionResult, so what should i do instead? should i do this with tempdata TempData["Message"] = "You can't make anymore polls.";
First, instead of returning
untyped
ActionResult
Return a typed one
ActionResult<T>
where T is the expected response
In the model of your response, you can have a string? ErrorMsg
and just populate the propwhy do i need to put <T> ?
Wait, sorry you're using MVC, not Web API, keep
ActionResult
thenok
i dont reall yunderstand what you said to do can you explain it again please
i mean with this
.
This is your database model right?
yes
i just added ErrorMsg
Alright, instead of adding ErrorMsg to your database model, make another model a
DTO
DataTransferObject
that model, let's called it PollDTO
would only return the relevant data that the view needs
And map your Poll
(database model) to the DTO PollDTO
In the DTO you can add the ErrorMsg propok
one second
do you mean like this?
Yes, but instead of having a
Poll
propety, only add the props that the view needs, so let's say from your Poll
you only need Title
, FirstOption
, SecondOption
You'd make your DTO only have these 3 props in addition to the ErrorMsg propok
when you say prop, you mean the column?
is this what you meant
By prop I mean a property :InaNodFast:
YOu can remove the validation attributes from the DTO, DTO are just for transferring data, you don't need these attributes
ok
ok im done
what should i do next ?
are you there
@Kouhai /人◕ ‿‿ ◕人\
Sorry, was afk
Okay so right now you can just return that DTO after mapping the data from your Database model
But there comes a problem
If
ErrorMsg
is not null it means an error happened, and we shouldn't have any of the other data
So we can refactor this a bit
And instead of return just out DTO, we can now remove ErrorMsg from PollDTO
And instead return a Result<PollDTO>
And we can use the two static methods Ok
and Error
to easily do thatok
to be honest i dont really know what any of these mean, do i have to understand itt right now?
What's the confusion part?
DTO
s in general or why we use Result<T>
?i dont know what <T> is, and why there is a public variable of type T called Data. and i dont kno wwhat {get, set} really (i think i do but maybe its wrong), but it seem sliek you are only using get for this. and why is it public static? i thought it was either public or static. public means other class instances can access thhe method, but static means they cant. so why do we have both? and what is Data = data? looks like you are passing something to the result method and setting data based on that?
Alright,
So for the first part what does
{get; set;}
mean
In C# we have what's called an auto property, We can get
a value from it and set
to it {get; set;}
get
is called a getter
, set
is called a setter
We can restrict the visibility to them, for instance let's say we have this class
Any piece of code that has access to a User
instance can assign anything to the Name
property
What happens if we only want Name to be assigned once, only when the instance is created, we can just completely remove the setter
The prop is now readonly, it can only be assigned a value when the object is getting created in the example above, that's happening in the constructor.
No for the second part what does public static
mean
public
is an access modifier it means any piece of code can access that member
static
means something entirely different, it means the member lives on the type itself NOT the type instanceok
For example
No lastly for what is
<T>
these are called generics, and honestly, I won't be good enough to explain them like how the docs explain them so I would highly highly suggest reading the docs on generics
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/generics
But to give you an example of why they are essential
We want some sort of container that stores 3 instances of our User
class, well we could just do
That's easy enough, but we also now want a 3 segmented container to store our Album
instances
We can copy the code, change the class name to something like AlubmThreeSegmentsContainer
and change the members to
But that's tedious, and does make sense to keep replicating the same stuff everytime we want a three segment container
What happens if there is a shorter way to do that?
An easy approach would be
Well all types in c# inhreint from Object
so we just assign these three properties whatever we want...but there is another problem, no we have lost the type, we'd need to check it at runtime, well the alternative is actually to use generics, we can introduce a type
as a parameter
Now all we have to do is pass in the type to our class
oh so kind of lik ea dynamic type
No, not dynamic in fact generics are used to avoid needing dynamic types
Because when we access
One
in userContainer
it 1000000% is of the type User
it can never ever be Album
because it was created with the generic type of User
by dynamic i mean that if you pass <User>, it will generate public User One, public User Two, etc
and if you pass <Album> it will do soemthing similar but with album
Exactly :InaNodFast:
i have to go now i wish it wasnt so late but i will read mor eabout generics tomorrow. but we didnt get to finish the DTO but maybe you will be here tomorrow. but what i wanted to ask was:
why did you not do this? instead of what you had above? where you removed the set and kept it as a public variable? also, could you not make a custom method to set the variable, instea dof using
set
? what is the difference?Well the actual c# keyword
readonly
can't be used with properties, they keyword readonly
can be used with fields
And for using a method instead of using set
, well in most cases there's barely any reason to use a prop, would you prefer for example to do
or
ok that makes sense for the set byt for the readonly
i said that because of this
i saw it hete thats why
thanks im gone for now
Take care! :Wave:
Btw, these are fields not props
private readonly ILogger<HomeController> _logger;
ok
i did some research and they are fields because you cant access them outside of the class i think right? but properties can be accessed otuside of the class with get/set
also im not usre if you are still here but can we continue this please thanks
You shouldn't access fields outside your class yes, but it's not enforced by the compiler or the runtime unless you have an access modifier like
private
to enforce thatok
do you have time to help me please i am stil stuck on this part where i want to tell the user that they cant make anymore polls if the db has 25 or more. I made the PollDTO but i am not sure what to do next in the controller thanks
Of course :InaNod:
Did you also create the
Result<T>
helper type so we can easily return both valid data and errors if needed?no i forgot i have to add this one
i am not sure if i am doing this right but it says that Ok, Data, Error, are not defined
Sorry it needs to be like this
ok it says
oh
i mean
ok there are no more errrors anymore
In your controller, you can now do for example
This will create a Result object with the error messge "Invalid data"
ok i tried doing this but it says
ok i am probably doing this wrong i think
Well, you won't return it as an ActionResult, you'd return it as a model in your view
your controller return ActionResult
And this is an MVC project, so we return a Model for the View
The model in this case is of type
Result<PollDTO>
But you need to return a view
In your original code
ok i did something like this, and it doesnt give any errors
Does your view correctly use the data from the
Result<PollDTO>
model instance?
By default the view doesn't really know how to use the data in the model
You need to do that manuallyoh
so what data does the view know how to handle?
is it the models you defiined?
in /models folder?
so when you declrare the model here, you are tellign the view what model to use?
and the controller sends the PollItem model for exmaple to the view?
The view by itself doesn't really do anything, the programmer needs to construct the way to show said data
In your github repo, you have something like this
Here you're defining ErrorViewModel as the model for the Error view, you're also getting the RequestId from the model
Yup spot on
ok
i didnt make this, it was alread installed when i startred th eporject. but i use it for exception block
Oh okay
one second
I dont think that there is a way i can iimport two views, so maybe i have to combine them into one? do you think so?
`@model realTimePolls.Models.PollItem;
@model realTimePolls.Models.PollDTO
@{
var userId = ViewData["UserId"];
}
<div class="main">
<div class="card">
<div class="container">
@if (Model.Poll.Genre != null)
{
<h2 class="fw-bold genre-heading">G`
....................
i think that i have to combine PollItem and PollDTO
into one modelYeah you can't have two models, is a PollItem the model from the database?
no
Poll Item is a class that has Poll <- which is from the db and then it has additional properties that are not from the database
i mean everyting in PollItem except for Poll is not in the database schema
Well, that should be your PollDTO then :InaNod:
Make sure to remove ErrorMsg from the Poll database model btw
ok
so i need to add PollItem props to PollDTO. and then use PollDTO only in the view @ import?
Right you'd add your new model
@model ......
ok, PollItem is being used in some places, so i should fix them so that it uses PollDTO instead?
one seocnd i will fix polldto first
Hard to tell, the DTO should only be for transfering data, but maybe PollItem is used differently
ok
poll item is used for getting a poll and then stuff for that poll, like the vote count
it is used in several controllers lik ethis:
i am so confused
im still confused i think i am goign to go to bed now though, im not sure what i am doing tbh
it is complicated to me but i will try again tomorrow
i did something like this i dont think it looks good i propbably need to clean it up but. now that i realized that i dont want to return any view if there are errors because the create form is not a view, it is part of the layout. so its on every page. im not really sure how i would do it in this case then
i wish there was a way to make it not continue the request and just cancel the operation and send a message back to the user, without showing an exception screen, because they didnt do anything wrong i think
ok the real reason i wanted to do any of this is because
my pagination widget is held together by a bunch of client side code and it works fine but i didnt consider what should happen if you have 100 pages of data
and trying to implement the thing where it only shows some of the numbers instead of all of them would probably take a lot of time and i feel like it would break things i already did
so i thought that maybe i should just limit the amount of pages to 5 so that there is no reason to implement that functionality at all
but that doesnt really make any sense now that i think about it
so i think i will just try to fix the pagination so it doesnt show literally all of the page numbers at the same time
i dont think it made sense for me to return the view anyways cause the create poll form is not a seperate page, its just in the shared layout
i didnt like this wrapping so i thought the solution was to limit the amount of pages by limiting the amount of polls but i dont think that makes sense to do
maybe i should find a library, instead of trying to make it from scratch
Hey sorry was a bit busy yesterday 😅
If you only wanted to return an error because of the page count wrapping, then you should instead display fewer pages, then when the user navigates to page 2 for example you also show page 7 on the page counter bellow