C
C#9mo ago
Ares

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.
Controller
[HttpPost]
public ActionResult Create(
[FromForm] string title,
[FromForm] string firstOption,
[FromForm] string secondOption,
[FromForm] int genre
)
{
try
{
var googleId =
HttpContext != null ? HttpContext.User.Claims.ToList()[0].Value : string.Empty;

if (googleId == string.Empty)
throw new Exception("Could not find googleId");

int userId = _context.User.SingleOrDefault(u => u.GoogleId == googleId).Id;

var pollGenre = _context.Genre.SingleOrDefault(g => g.Id == genre);

Poll poll = new Poll
{
UserId = userId,
Title = title,
FirstOption = firstOption,
SecondOption = secondOption,
GenreId = pollGenre.Id,
};

_context.Polls.Add(poll);
_context.SaveChanges();

return RedirectToAction(
"Index",
new
{
polltitle = poll.Title,
pollid = poll.Id,
userid = poll.UserId,
genreName = pollGenre.Name,
}
);
}
catch (Exception e)
{
var errorViewModel = new ErrorViewModel { RequestId = e.Message };
return View("Error", errorViewModel);
}
}
Controller
[HttpPost]
public ActionResult Create(
[FromForm] string title,
[FromForm] string firstOption,
[FromForm] string secondOption,
[FromForm] int genre
)
{
try
{
var googleId =
HttpContext != null ? HttpContext.User.Claims.ToList()[0].Value : string.Empty;

if (googleId == string.Empty)
throw new Exception("Could not find googleId");

int userId = _context.User.SingleOrDefault(u => u.GoogleId == googleId).Id;

var pollGenre = _context.Genre.SingleOrDefault(g => g.Id == genre);

Poll poll = new Poll
{
UserId = userId,
Title = title,
FirstOption = firstOption,
SecondOption = secondOption,
GenreId = pollGenre.Id,
};

_context.Polls.Add(poll);
_context.SaveChanges();

return RedirectToAction(
"Index",
new
{
polltitle = poll.Title,
pollid = poll.Id,
userid = poll.UserId,
genreName = pollGenre.Name,
}
);
}
catch (Exception e)
{
var errorViewModel = new ErrorViewModel { RequestId = e.Message };
return View("Error", errorViewModel);
}
}
70 Replies
Ares
Ares9mo ago
https://github.com/ForkEyeee/realtime-poll/blob/main/realTimePollsApp/Controllers/PollController.cs https://github.com/ForkEyeee/realtime-poll/blob/main/realTimePollsApp/Views/Shared/_Layout.cshtml
View
@using (Html.BeginForm("Create", "Poll", FormMethod.Post))
{
<div>
@Html.Label("Title", "Poll Title", new { @class = "required" })
@Html.TextBox("Title", string.Empty, new { @class = "input-class", @required = "required", @maxLength = 50 })
</div>
<div>
@Html.Label("FirstOption", "First Option", new { @class = "required" })
@Html.TextBox("FirstOption", string.Empty, new { @class = "input-class", @required = "required", @maxLength = 20 })
</div>
<div>
@Html.Label("SecondOption", "Second Option", new { @class = "required" })
@Html.TextBox("SecondOption", string.Empty, new { @class = "input-class", @required = "required", @maxLength = 20 })
</div>
<div class="d-flex flex-column">
@Html.Label("genre", "Genre", new { @class = "required" })
<select id="genre" name="genre" class="Genre">
<option disabled="disabled" selected="selected">Choose a genre</option>
</select>
</div>
<div class="d-flex justify-content-end gap-3">
<input type="button" id="cancel-btn" value="Cancel" class="btn btn-secondary" />
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
}
View
@using (Html.BeginForm("Create", "Poll", FormMethod.Post))
{
<div>
@Html.Label("Title", "Poll Title", new { @class = "required" })
@Html.TextBox("Title", string.Empty, new { @class = "input-class", @required = "required", @maxLength = 50 })
</div>
<div>
@Html.Label("FirstOption", "First Option", new { @class = "required" })
@Html.TextBox("FirstOption", string.Empty, new { @class = "input-class", @required = "required", @maxLength = 20 })
</div>
<div>
@Html.Label("SecondOption", "Second Option", new { @class = "required" })
@Html.TextBox("SecondOption", string.Empty, new { @class = "input-class", @required = "required", @maxLength = 20 })
</div>
<div class="d-flex flex-column">
@Html.Label("genre", "Genre", new { @class = "required" })
<select id="genre" name="genre" class="Genre">
<option disabled="disabled" selected="selected">Choose a genre</option>
</select>
</div>
<div class="d-flex justify-content-end gap-3">
<input type="button" id="cancel-btn" value="Cancel" class="btn btn-secondary" />
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
}
Kouhai
Kouhai9mo ago
Essentially you want to retain the form state if there were any exceptions?
Ares
Ares9mo ago
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
Kouhai
Kouhai9mo ago
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
Kouhai
Kouhai9mo ago
Ares
Ares9mo ago
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
Kouhai
Kouhai9mo ago
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
Ares
Ares9mo ago
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.";
Kouhai
Kouhai9mo ago
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 prop
Ares
Ares9mo ago
why do i need to put <T> ?
Kouhai
Kouhai9mo ago
Wait, sorry you're using MVC, not Web API, keep ActionResult then
Ares
Ares9mo ago
ok
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace realTimePolls.Models
{
public class Poll
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int? Id { get; set; }

[ForeignKey("user")]
[Column("userid")]
public int UserId { get; set; }

[NotMapped] //navigation property
public User User { get; set; }

[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public Genre Genre { get; set; }

[NotMapped]
public string? ErrorMsg { get; set; } <--- i addded this
}
}
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace realTimePolls.Models
{
public class Poll
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int? Id { get; set; }

[ForeignKey("user")]
[Column("userid")]
public int UserId { get; set; }

[NotMapped] //navigation property
public User User { get; set; }

[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public Genre Genre { get; set; }

[NotMapped]
public string? ErrorMsg { get; set; } <--- i addded this
}
}
.....
var googleId =
HttpContext != null ? HttpContext.User.Claims.ToList()[0].Value : string.Empty;

if (googleId == string.Empty)
throw new Exception("Could not find googleId");

int userId = _context.User.SingleOrDefault(u => u.GoogleId == googleId).Id;

var pollGenre = _context.Genre.SingleOrDefault(g => g.Id == genre);

Poll poll = new Poll
{
UserId = userId,
Title = title,
FirstOption = firstOption,
SecondOption = secondOption,
GenreId = pollGenre.Id,
ErrorMsg = string.Empty
};
.....
var googleId =
HttpContext != null ? HttpContext.User.Claims.ToList()[0].Value : string.Empty;

if (googleId == string.Empty)
throw new Exception("Could not find googleId");

int userId = _context.User.SingleOrDefault(u => u.GoogleId == googleId).Id;

var pollGenre = _context.Genre.SingleOrDefault(g => g.Id == genre);

Poll poll = new Poll
{
UserId = userId,
Title = title,
FirstOption = firstOption,
SecondOption = secondOption,
GenreId = pollGenre.Id,
ErrorMsg = string.Empty
};
i dont reall yunderstand what you said to do can you explain it again please i mean with this .
Kouhai
Kouhai9mo ago
public class Poll
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int? Id { get; set; }

[ForeignKey("user")]
[Column("userid")]
public int UserId { get; set; }

[NotMapped] //navigation property
public User User { get; set; }

[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public Genre Genre { get; set; }

[NotMapped]
public string? ErrorMsg { get; set; } <--- i addded this
}
public class Poll
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int? Id { get; set; }

[ForeignKey("user")]
[Column("userid")]
public int UserId { get; set; }

[NotMapped] //navigation property
public User User { get; set; }

[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public Genre Genre { get; set; }

[NotMapped]
public string? ErrorMsg { get; set; } <--- i addded this
}
This is your database model right?
Ares
Ares9mo ago
yes i just added ErrorMsg
Kouhai
Kouhai9mo ago
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 prop
Ares
Ares9mo ago
ok one second
//Models/PollDTO
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.Tracing;

namespace realTimePolls.Models
{
public class PollDTO
{
public Poll Poll { get; set; }

public string? ErrorMsg { get; set; }

}
}
//Models/PollDTO
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.Tracing;

namespace realTimePolls.Models
{
public class PollDTO
{
public Poll Poll { get; set; }

public string? ErrorMsg { get; set; }

}
}
do you mean like this?
Kouhai
Kouhai9mo ago
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 prop
Ares
Ares9mo ago
ok
namespace realTimePolls.Models
{
public class PollDTO
{
[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public string? ErrorMsg { get; set; }
}
}
namespace realTimePolls.Models
{
public class PollDTO
{
[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public string? ErrorMsg { get; set; }
}
}
when you say prop, you mean the column? is this what you meant
Kouhai
Kouhai9mo ago
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
Ares
Ares9mo ago
ok
namespace realTimePolls.Models
{
public class PollDTO
{
public string Title { get; set; }

public string FirstOption { get; set; }

public string SecondOption { get; set; }

public int? GenreId { get; set; }

public string? ErrorMsg { get; set; }
}
}
namespace realTimePolls.Models
{
public class PollDTO
{
public string Title { get; set; }

public string FirstOption { get; set; }

public string SecondOption { get; set; }

public int? GenreId { get; set; }

public string? ErrorMsg { get; set; }
}
}
ok im done what should i do next ? are you there @Kouhai /人◕ ‿‿ ◕人\
Kouhai
Kouhai9mo ago
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
public class PollDTO
{
public string Title { get; set; }

public string FirstOption { get; set; }

public string SecondOption { get; set; }

public int? GenreId { get; set; }

public string? ErrorMsg { get; set; }
}
public class PollDTO
{
public string Title { get; set; }

public string FirstOption { get; set; }

public string SecondOption { get; set; }

public int? GenreId { get; set; }

public string? ErrorMsg { get; set; }
}
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
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }
public static Result<T> Ok<T>(T data)
{
Data = data;
}
public static Result<T> Error<T>(string errorMsg)
{
ErrorMsg = errorMsg;
}
}
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }
public static Result<T> Ok<T>(T data)
{
Data = data;
}
public static Result<T> Error<T>(string errorMsg)
{
ErrorMsg = errorMsg;
}
}
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 that
Ares
Ares9mo ago
ok to be honest i dont really know what any of these mean, do i have to understand itt right now?
Kouhai
Kouhai9mo ago
What's the confusion part? DTOs in general or why we use Result<T>?
Ares
Ares9mo ago
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?
Kouhai
Kouhai9mo ago
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
public class User
{
public string Name {get;set;}
}
public class User
{
public string Name {get;set;}
}
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
public class User
{
public string Name { get; }
public User(string name)
{
Name = name;
}
}
public class User
{
public string Name { get; }
public User(string name)
{
Name = name;
}
}
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 instance
Ares
Ares9mo ago
ok
Kouhai
Kouhai9mo ago
For example
public class User
{
public void Hi() // <---- This is an instance method
{
Console.WriteLine("hello from instance");
}
public static void StaticHi() // <----- This is a static method
{
Console.WriteLine("hello from static");
}
}

var user = new User();
user.Hi(); // <---- This is a call to an instance method
User.StaticHi(); // <---- This is a call to a static method, notice that we are accessing StaticHi on the type itself no the insatnce user
public class User
{
public void Hi() // <---- This is an instance method
{
Console.WriteLine("hello from instance");
}
public static void StaticHi() // <----- This is a static method
{
Console.WriteLine("hello from static");
}
}

var user = new User();
user.Hi(); // <---- This is a call to an instance method
User.StaticHi(); // <---- This is a call to a static method, notice that we are accessing StaticHi on the type itself no the insatnce user
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
public class UserThreeSegmentsContainer()
{
public User One {get;set;}
public User Two {get;set;}
public User Three {get;set;}
}
public class UserThreeSegmentsContainer()
{
public User One {get;set;}
public User Two {get;set;}
public User Three {get;set;}
}
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
public Album One {get;set;}
public Album Two {get;set;}
public Album Three {get;set;}
public Album One {get;set;}
public Album Two {get;set;}
public Album Three {get;set;}
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
public class GeneralThreeSegmentsContainer()
{
public Object One {get;set;}
public Object Two {get;set;}
public Object Three {get;set;}
}
public class GeneralThreeSegmentsContainer()
{
public Object One {get;set;}
public Object Two {get;set;}
public Object Three {get;set;}
}
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
public class GenericThreeSegmentsContainer<T> // <---- This means the class takes a type as a parameter, the paramter is called T you can named it
{ // whatever you'd like, typeically in C# we prefix it with T, but it's not a requirements
public T One {get;set;}
public T Two {get;set;}
public T Three {get;set;}
}
public class GenericThreeSegmentsContainer<T> // <---- This means the class takes a type as a parameter, the paramter is called T you can named it
{ // whatever you'd like, typeically in C# we prefix it with T, but it's not a requirements
public T One {get;set;}
public T Two {get;set;}
public T Three {get;set;}
}
Now all we have to do is pass in the type to our class
var userContainer = new GenericThreeSegmentsContainer<User>();
var albumContainer = new GenericThreeSegmentsContainer<Album>();
var userContainer = new GenericThreeSegmentsContainer<User>();
var albumContainer = new GenericThreeSegmentsContainer<Album>();
Ares
Ares9mo ago
oh so kind of lik ea dynamic type
Kouhai
Kouhai9mo ago
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
Ares
Ares9mo ago
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
Kouhai
Kouhai9mo ago
Exactly :InaNodFast:
Ares
Ares9mo ago
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:
public class User
{
private readonly string Name { get; set }
public User(string name)
{
Name = name;
}
}
public class User
{
private readonly string Name { get; set }
public User(string name)
{
Name = name;
}
}
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?
Kouhai
Kouhai9mo ago
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
user.SetName("The user's new name"):
user.SetName("The user's new name"):
or
user.Name = "The user's new name";
user.Name = "The user's new name";
Ares
Ares9mo ago
ok that makes sense for the set byt for the readonly i said that because of this
namespace realTimePolls.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;

private readonly RealTimePollsContext _context; // Declare the DbContext variable

public HomeController(ILogger<HomeController> logger, RealTimePollsContext context) // Inject DbContext in the constructor
{
_logger = logger;
_context = context; // Initialize the _context variable. This the DbContext instance.
}
namespace realTimePolls.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;

private readonly RealTimePollsContext _context; // Declare the DbContext variable

public HomeController(ILogger<HomeController> logger, RealTimePollsContext context) // Inject DbContext in the constructor
{
_logger = logger;
_context = context; // Initialize the _context variable. This the DbContext instance.
}
i saw it hete thats why thanks im gone for now
Kouhai
Kouhai9mo ago
Take care! :Wave: Btw, these are fields not props private readonly ILogger<HomeController> _logger;
Ares
Ares9mo ago
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
Kouhai
Kouhai9mo ago
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 that
Ares
Ares9mo ago
ok 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
Kouhai
Kouhai9mo ago
Of course :InaNod: Did you also create the Result<T> helper type so we can easily return both valid data and errors if needed?
Ares
Ares9mo ago
no i forgot i have to add this one
//Models/Result.cs
namespace realTimePolls.Models
{
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok<T>(T data)
{
Data = data;
}

public static Result<T> Error<T>(string errorMsg)
{
ErrorMsg = errorMsg;
}
}
}
//Models/Result.cs
namespace realTimePolls.Models
{
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok<T>(T data)
{
Data = data;
}

public static Result<T> Error<T>(string errorMsg)
{
ErrorMsg = errorMsg;
}
}
}
i am not sure if i am doing this right but it says that Ok, Data, Error, are not defined
Ares
Ares9mo ago
No description
Kouhai
Kouhai9mo ago
Sorry it needs to be like this
namespace realTimePolls.Models
{
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok<T>(T data)
{
return new Result<T>(data, null);
}

public static Result<T> Error<T>(string errorMsg)
{
return new Result<T>(null, errorMsg);
}
public Result<T>(T? data, string? errorMsg)
{
Data = data;
ErrorMsg = errorMsg;
}
}
}
namespace realTimePolls.Models
{
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok<T>(T data)
{
return new Result<T>(data, null);
}

public static Result<T> Error<T>(string errorMsg)
{
return new Result<T>(null, errorMsg);
}
public Result<T>(T? data, string? errorMsg)
{
Data = data;
ErrorMsg = errorMsg;
}
}
}
Ares
Ares9mo ago
ok it says
Severity Code Description Project File Line Suppression State
Error CS1729 'Result<T>' does not contain a constructor that takes 2 arguments realTimePolls C:\Users\Desktop\projects\RealTimePolls\realTimePollsApp\Models\Result.cs 10 Active
Severity Code Description Project File Line Suppression State
Error CS1729 'Result<T>' does not contain a constructor that takes 2 arguments realTimePolls C:\Users\Desktop\projects\RealTimePolls\realTimePollsApp\Models\Result.cs 10 Active
oh i mean
Ares
Ares9mo ago
No description
Ares
Ares9mo ago
No description
Kouhai
Kouhai9mo ago
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok(T data)
{
return new Result<T>(data, null);
}

public static Result<T> Error(string errorMsg)
{
return new Result<T>(default, errorMsg);
}
public Result(T? data, string? errorMsg)
{
Data = data;
ErrorMsg = errorMsg;
}
}
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok(T data)
{
return new Result<T>(data, null);
}

public static Result<T> Error(string errorMsg)
{
return new Result<T>(default, errorMsg);
}
public Result(T? data, string? errorMsg)
{
Data = data;
ErrorMsg = errorMsg;
}
}
Ares
Ares9mo ago
ok there are no more errrors anymore
Ares
Ares9mo ago
No description
Kouhai
Kouhai9mo ago
In your controller, you can now do for example
Result<PollDTO>.Error("Invalid data");
Result<PollDTO>.Error("Invalid data");
This will create a Result object with the error messge "Invalid data"
Ares
Ares9mo ago
[HttpPost]
public ActionResult Create(
[FromForm] string title,
[FromForm] string firstOption,
[FromForm] string secondOption,
[FromForm] int genre
)
{
try
{
if (_context.Polls.Count() >= 25)
return Result<PollDTO>.Error("Invalid data") as ActionResult;

var googleId =
HttpContext != null ? HttpContext.User.Claims.ToList()[0].Value : string.Empty;
............
[HttpPost]
public ActionResult Create(
[FromForm] string title,
[FromForm] string firstOption,
[FromForm] string secondOption,
[FromForm] int genre
)
{
try
{
if (_context.Polls.Count() >= 25)
return Result<PollDTO>.Error("Invalid data") as ActionResult;

var googleId =
HttpContext != null ? HttpContext.User.Claims.ToList()[0].Value : string.Empty;
............
ok i tried doing this but it says
Severity Code Description Project File Line Suppression State
Error CS0039 Cannot convert type 'Result<realTimePolls.Models.PollDTO>' to 'Microsoft.AspNetCore.Mvc.ActionResult' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion realTimePolls C:\Users\Desktop\projects\RealTimePolls\realTimePollsApp\Controllers\PollController.cs 128 Active
Severity Code Description Project File Line Suppression State
Error CS0039 Cannot convert type 'Result<realTimePolls.Models.PollDTO>' to 'Microsoft.AspNetCore.Mvc.ActionResult' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion realTimePolls C:\Users\Desktop\projects\RealTimePolls\realTimePollsApp\Controllers\PollController.cs 128 Active
ok i am probably doing this wrong i think
Kouhai
Kouhai9mo ago
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
catch (Exception e)
{
var errorViewModel = new ErrorViewModel { RequestId = e.Message };
return View("Error", errorViewModel); // <---- you're returning an Error view with the model ErrorViewModel
}
catch (Exception e)
{
var errorViewModel = new ErrorViewModel { RequestId = e.Message };
return View("Error", errorViewModel); // <---- you're returning an Error view with the model ErrorViewModel
}
Ares
Ares9mo ago
if (_context.Polls.Count() >= 25)
{
var viewModel = Result<PollDTO>.Error("Invalid data");
return View(viewModel);
}
if (_context.Polls.Count() >= 25)
{
var viewModel = Result<PollDTO>.Error("Invalid data");
return View(viewModel);
}
ok i did something like this, and it doesnt give any errors
Kouhai
Kouhai9mo ago
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 manually
Ares
Ares9mo ago
oh so what data does the view know how to handle? is it the models you defiined? in /models folder?
@model realTimePolls.Models.PollItem;
@{
var userId = ViewData["UserId"];
}
@model realTimePolls.Models.PollItem;
@{
var userId = ViewData["UserId"];
}
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?
Kouhai
Kouhai9mo ago
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
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
Here you're defining ErrorViewModel as the model for the Error view, you're also getting the RequestId from the model Yup spot on
Ares
Ares9mo ago
ok i didnt make this, it was alread installed when i startred th eporject. but i use it for exception block
Kouhai
Kouhai9mo ago
Oh okay
Ares
Ares9mo ago
one second
Severity Code Description Project File Line Suppression State
Error RZ2001 The 'model' directive may only occur once per document. realTimePolls C:\Users\Desktop\projects\RealTimePolls\realTimePollsApp\Views\Poll\Index.cshtml 2
Severity Code Description Project File Line Suppression State
Error RZ2001 The 'model' directive may only occur once per document. realTimePolls C:\Users\Desktop\projects\RealTimePolls\realTimePollsApp\Views\Poll\Index.cshtml 2
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 model
Kouhai
Kouhai9mo ago
Yeah you can't have two models, is a PollItem the model from the database?
Ares
Ares9mo ago
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
namespace realTimePolls.Models
{
public class PollItem
{
public Poll Poll { get; set; }
public int FirstVoteCount { get; set; }
public int SecondVoteCount { get; set; }

[NotMapped]
public virtual bool? Vote { get; set; }

[NotMapped]
public virtual string? UserName { get; set; }

[NotMapped]
public virtual string? ProfilePicture { get; set; }
}
}
namespace realTimePolls.Models
{
public class PollItem
{
public Poll Poll { get; set; }
public int FirstVoteCount { get; set; }
public int SecondVoteCount { get; set; }

[NotMapped]
public virtual bool? Vote { get; set; }

[NotMapped]
public virtual string? UserName { get; set; }

[NotMapped]
public virtual string? ProfilePicture { get; set; }
}
}
namespace realTimePolls.Models
{
public class Poll
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int? Id { get; set; }

[ForeignKey("user")]
[Column("userid")]
public int UserId { get; set; }

[NotMapped] //navigation property
public User User { get; set; }

[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public Genre Genre { get; set; }

[NotMapped]
public string? ErrorMsg { get; set; }
}
}
namespace realTimePolls.Models
{
public class Poll
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int? Id { get; set; }

[ForeignKey("user")]
[Column("userid")]
public int UserId { get; set; }

[NotMapped] //navigation property
public User User { get; set; }

[Required]
[Column("title")]
public string Title { get; set; }

[Required]
[Column("firstoption")]
public string FirstOption { get; set; }

[Required]
[Column("secondoption")]
public string SecondOption { get; set; }

[ForeignKey("genre")]
[Column("genreid")]
public int? GenreId { get; set; }

public Genre Genre { get; set; }

[NotMapped]
public string? ErrorMsg { get; set; }
}
}
i mean everyting in PollItem except for Poll is not in the database schema
Kouhai
Kouhai9mo ago
Well, that should be your PollDTO then :InaNod: Make sure to remove ErrorMsg from the Poll database model btw
Ares
Ares9mo ago
ok so i need to add PollItem props to PollDTO. and then use PollDTO only in the view @ import?
Kouhai
Kouhai9mo ago
Right you'd add your new model @model ......
Ares
Ares9mo ago
ok, PollItem is being used in some places, so i should fix them so that it uses PollDTO instead?
No description
Ares
Ares9mo ago
one seocnd i will fix polldto first
Kouhai
Kouhai9mo ago
Hard to tell, the DTO should only be for transfering data, but maybe PollItem is used differently
Ares
Ares9mo ago
using System.ComponentModel.DataAnnotations.Schema;
using realTimePolls.Models;

namespace realTimePolls
{
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok(T data)
{
return new Result<T>(data, null);
}

public static Result<T> Error(string errorMsg)
{
return new Result<T>(default, errorMsg);
}

public Result(T? data, string? errorMsg)
{
Data = data;
ErrorMsg = errorMsg;
}

public Poll Poll { get; set; }

[NotMapped]
public int FirstVoteCount { get; set; }

[NotMapped]
public int SecondVoteCount { get; set; }

[NotMapped]
public virtual bool? Vote { get; set; }

[NotMapped]
public virtual string? UserName { get; set; }

[NotMapped]
public virtual string? ProfilePicture { get; set; }
}
}
using System.ComponentModel.DataAnnotations.Schema;
using realTimePolls.Models;

namespace realTimePolls
{
public class Result<T>
{
public T? Data { get; }
public string? ErrorMsg { get; }

public static Result<T> Ok(T data)
{
return new Result<T>(data, null);
}

public static Result<T> Error(string errorMsg)
{
return new Result<T>(default, errorMsg);
}

public Result(T? data, string? errorMsg)
{
Data = data;
ErrorMsg = errorMsg;
}

public Poll Poll { get; set; }

[NotMapped]
public int FirstVoteCount { get; set; }

[NotMapped]
public int SecondVoteCount { get; set; }

[NotMapped]
public virtual bool? Vote { get; set; }

[NotMapped]
public virtual string? UserName { get; set; }

[NotMapped]
public virtual string? ProfilePicture { get; set; }
}
}
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:
var polls = _context
.Polls.Skip(skip)
.Include(p => p.Genre)
.Take(take)
.Select(p => new PollItem <---
{
Poll = p,
FirstVoteCount = _context
.UserPoll.Where(up => up.PollId == p.Id && up.Vote == true)
.Count(),
SecondVoteCount = _context
.UserPoll.Where(up => up.PollId == p.Id && up.Vote == false)
.Count(),
UserName = _context.User.SingleOrDefault(user => user.Id == p.UserId).Name,
ProfilePicture = _context
.User.SingleOrDefault(user => user.Id == p.UserId)
.ProfilePicture
})
.ToList();
var polls = _context
.Polls.Skip(skip)
.Include(p => p.Genre)
.Take(take)
.Select(p => new PollItem <---
{
Poll = p,
FirstVoteCount = _context
.UserPoll.Where(up => up.PollId == p.Id && up.Vote == true)
.Count(),
SecondVoteCount = _context
.UserPoll.Where(up => up.PollId == p.Id && up.Vote == false)
.Count(),
UserName = _context.User.SingleOrDefault(user => user.Id == p.UserId).Name,
ProfilePicture = _context
.User.SingleOrDefault(user => user.Id == p.UserId)
.ProfilePicture
})
.ToList();
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
if (_context.Polls.Count() >= 25)
{
PollItem viewModel = new PollItem();
var error = new realTimePolls.Result<string>("invalid data", "error message");
viewModel.ErrorMsg = error.ErrorMsg;
viewModel.Data = error.Data;
return View("index", viewModel);
}
if (_context.Polls.Count() >= 25)
{
PollItem viewModel = new PollItem();
var error = new realTimePolls.Result<string>("invalid data", "error message");
viewModel.ErrorMsg = error.ErrorMsg;
viewModel.Data = error.Data;
return View("index", viewModel);
}
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
Ares
Ares9mo ago
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
No description
Ares
Ares9mo ago
maybe i should find a library, instead of trying to make it from scratch
Kouhai
Kouhai9mo ago
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
Want results from more Discord servers?
Add your server