How to use model data in a view? - c#

I have HomeController and Index method:
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View();
}
}
It returns this page:
<form asp-controller="Player" asp-action="VideoPlayer" method="post">
<div class="demo-btns">
<div class="info">
<div class="buttons">
<p><input type="text" name="userName" placeholder="Name:" size="18" /></p>
<p><input type="text" name="roomCode" placeholder="Code of the room:" size="18" /></p>
<input type="submit" class="modal__trigger2" value="Join Room" />
</div>
</div>
</div>
</form>
PlayerController:
public class PlayerController : Controller
{
public static RoomData roomData = new RoomData();
public IActionResult VideoPlayer(string userName, string roomCode)
{
roomData.UserName = userName;
roomData.RoomCode = roomCode;
return View();
}
}
I'd like to show userName and roomCode on another page that is why I use PlayerController and VideoPlayer action
#using Watch.Models;
<div class="content-box-center-monitor">
<div>Model?.RoomData></div>
<div>Model?.RoomCode</div>
</div>
But it doesn't work. My final html looks like this and I don't know why:
<div class="content-box-center-monitor">
<div></div> // no data
<div></div> // no data
</div>

You need to return the model to the view
public class PlayerController : Controller
{
public static RoomData roomData = new RoomData();
public IActionResult VideoPlayer(string userName, string roomCode)
{
roomData.UserName = userName;
roomData.RoomCode = roomCode;
return View(roomData);
}
}
Then in VideoPlayer page
#model RoomData;
<div class="content-box-center-monitor">
<div>Model?.UserName</div>
<div>Model?.RoomCode</div>
</div>

Related

Is there a way to route all #model data to another controller from a View in MVC?

#model IEnumerable<Order>
#if (TempData["SuccesMessage"] != null)
{
<div class="alert alert-success">
<strong> Succes! </strong>#TempData["SuccesMessage"]
</div>
}
<div class="container p-4 border">
<div class="row pb-2">
<h1 class="text-primary">All Orders</h1>
</div>
<div class="col text-end pt-1">
<a asp-controller="RabbitMQ" asp-action="SendToRabbit" class="btn btn-primary"> Send all </a>
</div>
Is there a way to route the data in the IEnumerable Order to another Controller, using the send all button? or any other way?
You can use TempData to share the data from Action to Action and Controller to Controller. Just stored yout data in TempData and retrieved it in another controller method.
eg.
Method1Contoller
Public class Method1Contoller : Controller
{
public ActionResult Method1()
{
TempData["Method1Data"] = "Your data";// you can store anything in this
return RedirectToAction("Method2");
}
}
Method2Contoller
Public class Method2Contoller : Controller
{
public ActionResult Method2()
{
if (TempData["Method1Data"] != null)
{
string data= (string) TempData["Method1Data"];
...
return View();
}
}
}

Image won't upload to REST api

I'm having trouble to update the image of an author in my application. When I add the input field for files in my Razor pages the code doesn't jump to the OnPost method in the code behind. Without the file input field it does.
Below my code.
Razor page code:
#page
#model PersonalLibrary.Razor.Pages.Authors.EditModel
#{
}
<div class="container">
<h1>Edit</h1>
<h4>Author</h4>
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Author.Id" />
<div class="form-group">
<img src="#Html.DisplayFor(model => model.Author.Image)" />
<div class="file-field input-field">
<div class="btn">
<span>Browse</span>
<input asp-for="Author.Image" type="file" />
</div>
<div class="file-path-wrapper">
<input asp-for="Author.Image" class="file-path validate" type="text" placeholder="Upload file" />
</div>
</div>
</div>
<div class="form-group">
<label asp-for="Author.Name" class="control-label"></label>
<input asp-for="Author.Name" class="form-control" />
<span asp-validation-for="Author.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Author.Country" class="control-label"></label>
<input asp-for="Author.Country" class="form-control" />
<span asp-validation-for="Author.Country" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Author.DateOfBirth" class="control-label"></label>
<input asp-for="Author.DateOfBirth" class="datepicker form-control" />
<span asp-validation-for="Author.DateOfBirth" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Update" class="btn btn-primary" />
</div>
</form>
</div>
OnPost in the code behind:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
IFormFile image = (IFormFile)Author.Image;
var imageUri = $"{baseUri}/authors/{Author.Id}/images";
await WebApiClient.PutCallApi<Author, IFormFile>(imageUri, image);
var uri = $"{baseUri}/authors/{Author.Id}";
await WebApiClient.PutCallApi<Author, Author>(uri, Author);
return RedirectToPage("./Index");
}
Api controller methods:
[HttpPut("{id}")]
public async Task<IActionResult> PutAsync(AuthorRequestDto authorRequestDto)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var authorResponseDto = await _authorService.UpdateAsync(authorRequestDto);
return Ok(authorResponseDto);
}
[HttpPost("{id}/image"), HttpPut("{id}/image")]
public async Task<IActionResult> Image([FromRoute] Guid id, IFormFile image)
{
var author = await _authorService.AddOrUpdateImageAsync(id, image);
if (author == null)
{
return NotFound($"Author with ID {id} not found");
}
return Ok(author);
}
Any help welcome!
UPDATE
In the Edit.cshtml.cs file I've added a new BindProperty for the image.
namespace PersonalLibrary.Razor.Pages.Authors
{
public class EditModel : PageModel
{
private readonly string baseUri = Constants.ApiBaseUri.BaseUri;
[BindProperty]
public Author Author { get; set; }
[BindProperty]
public IFormFile Image { get; set; }
public async Task<IActionResult> OnGetAsync(Guid id)
{
if (id == null)
{
return NotFound();
}
var uri = $"{baseUri}/authors/{id}";
Author = await WebApiClient.GetApiResult<Author>(uri);
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var imageUri = $"{baseUri}/authors/{Author.Id}/image";
await WebApiClient.PutCallApi<IFormFile, IFormFile>(imageUri, Image);
//var uri = $"{baseUri}/authors/{Author.Id}";
//await WebApiClient.PutCallApi<Author, Author>(uri, Author);
return RedirectToPage("./Index");
}
}
}
I had to change the enctype for the form to "multipart/form-data" in the Edit.cshtml file, like shown below.
#page
#model PersonalLibrary.Razor.Pages.Authors.EditModel
#{
}
<div class="container">
<h1>Edit</h1>
<h4>Author</h4>
<form method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Author.Id" />
<div class="form-group">
<img src="#Html.DisplayFor(model => model.Author.Image)" />
<div class="file-field input-field">
<div class="btn">
<span>Browse</span>
<input asp-for="Image" type="file" />
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text"
placeholder="Upload file" />
</div>
</div>
</div>
<div class="form-group">
<input type="submit" value="Update" class="btn btn-primary" />
</div>
</form>
</div>
So now the Image property is filled with the image I want to upload, but it crashes when accessing the WebApiClient class.
namespace PersonalLibrary.Web.Helpers
{
public class WebApiClient
{
private static JsonMediaTypeFormatter GetJsonFormatter() {
var formatter = new JsonMediaTypeFormatter();
//prevent self-referencing loops when saving Json (Bucket -> BucketItem -> Bucket -> ...)
formatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return formatter;
}
public async static Task<T> GetApiResult<T>(string uri)
{
using (HttpClient httpClient = new HttpClient())
{
string response = await httpClient.GetStringAsync(uri);
return JsonConvert.DeserializeObject<T>(response, GetJsonFormatter().SerializerSettings);
}
}
public static async Task<TOut> PutCallApi<TOut, TIn>(string uri, TIn entity)
{
return await CallApi<TOut, TIn>(uri, entity, HttpMethod.Put);
}
public static async Task<TOut> PostCallApi<TOut, TIn>(string uri, TIn entity)
{
return await CallApi<TOut, TIn>(uri, entity, HttpMethod.Post);
}
public static async Task<TOut> DeleteCallApi<TOut>(string uri)
{
return await CallApi<TOut, object>(uri, null, HttpMethod.Delete);
}
private static async Task<TOut> CallApi<TOut, TIn>(string uri, TIn entity, HttpMethod httpMethod)
{
TOut result = default;
using (HttpClient httpClient = new HttpClient())
{
HttpResponseMessage response;
if (httpMethod == HttpMethod.Post)
{
response = await httpClient.PostAsync(uri, entity, GetJsonFormatter());
}
else if (httpMethod == HttpMethod.Put)
{
response = await httpClient.PutAsync(uri, entity, GetJsonFormatter());
}
else
{
response = await httpClient.DeleteAsync(uri);
}
result = await response.Content.ReadAsAsync<TOut>();
}
return result;
}
}
}
This is the error I'm receiving:
UnsupportedMediaTypeException: No MediaTypeFormatter is available to read an object of type 'IFormFile' from content with media type 'application/problem+json'.
System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
My guess is the problem is I use a JsonMediaTypeFormatter. But I can't figure out what to use to handle files or images.

How to show a temporally Success Message without using query parameters?

I want to show a success message in a view SingIn.cshtml only one time after user registration. In order to do it, i was thinking into sending a boolean parameter to the SingIn Action method so then the View SingIn.cshtml will get it, and then choose if it should show it or not, but since the parameter will appear in the query string (app.com/Account/SignIn?parameter=true), the user can refresh the page and see it again and again or maybe he can type the url and saw it again.So How can i complete my approach without showing the parameter on a query string (app.com/Account/SignIn) ?
This is my Controller:
public class AccountController : Controller
{
private readonly SignInManager<Client> _signInManager;
private readonly UserManager<Client> _userManager;
public AccountController(UserManager<Client> userManager, SignInManager<Client> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
[HttpGet]
public IActionResult SignUp()
{
return View(new SignUpViewModel());
}
[HttpPost]
public async Task<IActionResult> SignUp(SignUpViewModel viewModel)
{
if (ModelState.IsValid)
{
var client = new Client
{
UserName = viewModel.Id, FullName = viewModel.FullName, BirthDate = viewModel.BirthDate.Value,
Email = viewModel.Email
};
var result = await _userManager.CreateAsync(client, viewModel.Password);
if (result.Succeeded)
return RedirectToAction("SignIn", new {DidHeJustSignUp = true});
}
return View(viewModel);
}
[HttpGet]
public IActionResult SignIn(bool didHeJustSignUp)
{
var model = new SignInViewModel {DidHeJustSignUp = didHeJustSignUp};
return View(model);
}
}
This is my view:
#model SignInViewModel
#{
ViewBag.Title = "Sign In";
}
<form asp-controller="Account" asp-action="SignIn" method="post">
#{
if (Model.DidHeJustSignUp)
{
<div class="alert alert-success text-center">
You have been registred Successfully, please Sign In
</div>
}
}
<div class="form-group">
<label asp-for="Id"></label>
<input type="text" class="form-control" asp-for="Id">
<span class="text-danger" asp-validation-for="Id"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input type="password" class="form-control" asp-for="Password"/>
<span class="text-danger" asp-validation-for="Password"></span>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" asp-for="ShouldIRememberYou">
<label class="form-check-label" asp-for="ShouldIRememberYou">Remember me</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
You can use TempData here, anything you put into TempData is discarded after the next request completes.
if (result.Succeeded)
{
TempData["DidHeJustSignUp"] = true;
return RedirectToAction("SignIn");
}
if (TempData["DidHeJustSignUp"] != null)
{
<div class="alert alert-success text-center">
You have been registred Successfully, please Sign In
</div>
}

How do i pass two text inputs into ActionResult method

I've been working on a large project for a few days. Its all finished except for this part. I'm trying to pass 2 text boxes into my home controller method.
I've tried to use "model." and "item." but with no luck. it always passes null
<p>
#Html.ActionLink("Display", "Home", FormMethod.Post)
</p>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div>
Month:<input type="text" name="Month" id="MonthInput">
Extra:<input type="text" name="Extra" id="ExtraInput"><br /><br />
<input type="submit" value="Add" class="btn btn-default"> <br> <br>
</div>
}
and in the home controller is
[HttpPost]
public ActionResult Display(String Month, String Extra)
{
if (ModelState.IsValid)
{
...
return RedirectToAction("Index");
}
return view;
}
I want it to pass whatever value is typed in the textboxes when the "Add" Button is clicked but it gives null
try this,
In View
#using (Html.BeginForm("Display", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
Month:<input type="text" name="Month" id="MonthInput">
Extra:<input type="text" name="Extra" id="ExtraInput"><br /><br />
<input type="submit" value="Add" class="btn btn-default"> <br> <br>
</div>
}
In Controller,
[HttpPost]
public ActionResult Display(SomeClass someClass)
{
if (ModelState.IsValid)
{
...
return RedirectToAction("Index");
}
return view;
}
Create Normal class name SomeClass, name as per your requirment,
public class SomeClass{
public string Month {get;set;}
public string Extra {get;set;}
}
the name attribute of inputs should match to properties of SomeClass, it will map automatically, you then can access the value by using someClass object
someClass.Month and someClass.Extra
In order to correctly map to the action's parameters, you must use the name attribute.
#using (Html.BeginForm("Display", "Home"))
{
#Html.AntiForgeryToken()
<div>
Month:<input type="text" name="Month" id="MonthInput">
Extra:<input type="text" name="Extra" id="ExtraInput"><br /><br />
<input type="submit" value="Add" class="btn btn-default">
</div>
}
Totally unrelated, but it seems you have 2 nested forms and one of them POSTs to a php page. Is that desired?
Also, remove the following code because it does not make any sense:
<p>
#Html.ActionLink("Display", "Home", FormMethod.Post)
</p>
To add on to the previous answer, I would suggest accepting the form as a FormCollection in the controller, because the form does not seem to be tied to the model:
[HttpPost]
public ActionResult Display(FormCollection collection)
{
if (ModelState.IsValid)
{
string month = collection["Month"];
string extra = collection["Extra"];
return RedirectToAction("Index");
}
return View();
}
namespace Your.Models
{
public class DisplayModel
{
public string Month {get;set;}
public string Extra {get;set;}
}
}
[HttpPost]
public ActionResult Display(DisplayModel model)
{
if (ModelState.IsValid)
{
string month = model.Month;
string extra = model.Extra;
return RedirectToAction("Index");
}
return View();
}
#using Your.Models
#model DisplayModel
#using (Html.BeginForm("Display", "Home", new { id="displayview" }))
{
#Html.AntiForgeryToken()
<div>
Month:<input type="text" name="Month" id="MonthInput">
Extra:<input type="text" name="Extra" id="ExtraInput"><br /><br />
<input type="submit" value="Add" class="btn btn-default">
</div>
}

Sending a phrase (variable) from searcher (from view) to controller, asp.net mvc

I'm trying to create searcher in asp.net. I'm so green about it. I'm trying to create in view and send to controller variable, which has text written in searcher. In that moment, I have smth like that -->
My question is, where and how create and send variable and give her data written in searcher?
Layout
form class="navbar-form navbar-left" role="search">
#using (Html.BeginForm("Index", "Searcher", FormMethod.Post, new { phrase = "abc" }))
{
<div class="form-group">
<input type="text" class="form-control" placeholder="Wpisz frazę...">
</div>
<button type="submit" class="btn btn-default">#Html.ActionLink("Szukaj", "Index", "Searcher")</button>
}
</form>
Controller
public class SearcherController : ApplicationController
{
[HttpGet]
public ActionResult Index(string message)
{
ViewBag.phrase = message;
getCurrentUser();
return View();
}
}
View
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<ul>
<li>#ViewBag.message</li>
</ul>
You're missing a key part of MVC -> the Model.
Let's create one first:
public class SearchModel
{
public string Criteria { get; set; }
}
Then let's update your "Layout" view (don't know why you had a form in a form?):
#model SearchModel
#using (Html.BeginForm("Index", "Searcher", FormMethod.Post, new { phrase = "abc" }))
{
<div class="form-group">
#Html.EditorFor(m => m.Criteria)
</div>
<button type="submit" class="btn btn-default">#Html.ActionLink("Szukaj", "Index", "Searcher")</button>
}
Then your action that serves that view:
[HttpGet]
public ActionResult Index()
{
return View(new SearchModel());
}
Then your post method would be:
[HttpPost]
public ActionResult Index(SearchModel model)
{
ViewBag.phrase = model.Criteria;
getCurrentUser();
return View();
}

Categories

Resources