Image won't upload to REST api - c#

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.

Related

Data not being passed from Razor page

I have a Blazor app that takes user input via a form field and puts it into a database.
However, the data is not being passed from the front end correctly:
Razor file
#using Blogs.Shared.Models
#page "/addpost"
#inject HttpClient Http
#inject NavigationManager NavigationManager
<h2>Create Post</h2>
<hr />
<div class="row">
<div class="col-md-4">
<form>
<div class="form-group">
<label for="Name" class="control-label">Titles</label>
<input for="Name" class="form-control" bind="#posts.title" />
</div>
<div class="form-group">
<label for="Address" class="control-label">Content</label>
<input for="Address" class="form-control" bind="#posts.content" />
</div>
<div class="form-group">
<input type="button" class="btn btn-default" onclick="#(async () => await tas())" value="Save" />
<input type="button" class="btn" onclick="#Cancel" value="Cancel" />
</div>
</form>
</div>
</div>
#functions {
public Posts posts = new();
protected async Task tas()
{
await Http.PostAsJsonAsync("api/Posts/Create", posts);
NavigationManager.NavigateTo("/listposts");
}
void Cancel()
{
NavigationManager.NavigateTo("/listposts");
}
}
What I would expect this to do, is when Save is pressed, the data from Title and Content is assigned to posts and then passed to my POST method:
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Blogs.Shared.Models;
using Microsoft.AspNetCore.Mvc;
namespace Blogs.Server.Controllers
{
public class PostsController : Controller
{
private readonly IDataAccessProvider _dataAccessProvider;
private readonly ILogger _logger;
public PostsController(IDataAccessProvider dataAccessProvider, ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger("PostsController");
_dataAccessProvider = dataAccessProvider;
}
[HttpPost]
[Route("api/Posts/Create")]
public void Create(Posts post)
{
_logger.LogCritical("Data 1", post);
_logger.LogCritical("Data 2", post.content);
_logger.LogCritical("Data 3", post.title);
_dataAccessProvider.AddPosts(post);
}
}
}
All of my _logger.LogCritical lines just return blank, and when the write to the DB occurs it complains that title is empty (this field in my DB is set to NOT NULL).
Can anyone help as to why this is not working?
EDIT
I have updated the code to better match Antoine B's suggestions but its still not working:
#page "/newpost"
#using Blogs.Shared.Models
#inject HttpClient Http
#inject NavigationManager NavigationManager
<h1>#Title Post</h1>
<hr />
<EditForm Model="#posts" OnValidSubmit="SaveUser">
<DataAnnotationsValidator />
<div class="mb-3">
<label for="Name" class="form-label">Title</label>
<div class="col-md-4">
<InputText class="form-control" #bind-Value="posts.title" />
</div>
<ValidationMessage For="#(() => posts.title)" />
</div>
<div class="mb-3">
<label for="Address" class="form-label">Content</label>
<div class="col-md-4">
<InputText class="form-control" #bind-Value="posts.content" />
</div>
<ValidationMessage For="#(() => posts.content)" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Save</button>
<button class="btn btn-light" #onclick="Cancel">Cancel</button>
</div>
</EditForm>
#code {
protected string Title = "Add";
protected Posts posts = new();
protected async Task SaveUser()
{
await Http.PostAsJsonAsync("api/Posts/Create", posts);
Cancel();
}
public void Cancel()
{
NavigationManager.NavigateTo("/listposts");
}
}
To bind a value to an input component you must add an # before the bind property, like following #bind="posts.title" (see https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-6.0)
That's what's not working for you.
I also don't recommend you to use the #functions because it is not recommended by Microsoft for razor files (see https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-3.0#functions)
#code {
public Posts posts = new();
protected async Task tas()
{
await Http.PostAsJsonAsync("api/Posts/Create", posts);
NavigationManager.NavigateTo("/listposts");
}
void Cancel()
{
NavigationManager.NavigateTo("/listposts");
}
}
I hope it helped you

Image is not added / read in image upload field (asp.net)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using eCom.Data;
using eCom.Models;
using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment;
namespace eCom.Areas.Admin.Controllers
{
[Area("Admin")]
public class ProductController : Controller
{
private ApplicationDbContext _db;
private IHostingEnvironment _he;
public ProductController(ApplicationDbContext db, IHostingEnvironment he)
{
_db = db;
_he = he;
}
public IActionResult Index()
{
return View(_db.Products.Include(c => c.ProductTypes).Include(f => f.SpecialTag).ToList());
}
//POST Index action method
[HttpPost]
public IActionResult Index(decimal? lowAmount, decimal? largeAmount)
{
var products = _db.Products.Include(c => c.ProductTypes).Include(c => c.SpecialTag)
.Where(c => c.Price >= lowAmount && c.Price <= largeAmount).ToList();
if (lowAmount == null || largeAmount == null)
{
products = _db.Products.Include(c => c.ProductTypes).Include(c => c.SpecialTag).ToList();
}
return View(products);
}
//Get Create method
public IActionResult Create()
{
ViewData["productTypeId"] = new SelectList(_db.ProductTypes.ToList(), "Id", "ProductType");
ViewData["TagId"] = new SelectList(_db.SpecialTag.ToList(), "Id", "Tag");
return View();
}
//Post Create method
[HttpPost]
public async Task<IActionResult> Create(Products products, IFormFile image)
{
if (ModelState.IsValid)
{
/*var searchProduct = _db.Products.FirstOrDefault(c => c.Tag == products.Tag);
if (searchProduct != null)
{
ViewBag.message = "This product is already exist";
ViewData["productTypeId"] = new SelectList(_db.ProductTypes.ToList(), "Id", "ProductType");
ViewData["TagId"] = new SelectList(_db.SpecialTag.ToList(), "Id", "Tag");
return View(products);
}*/
if (image != null)
{
var name = Path.Combine(_he.WebRootPath + "/Images", Path.GetFileName(image.FileName));
await image.CopyToAsync(new FileStream(name, FileMode.Create));
products.Image = "Images/" + image.FileName;
}
/*if (image == null)
{
products.Image = "Images/noimage.PNG";
}*/
_db.Products.Add(products);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(products);
}
I'm trying to make a website with asp.net. I'm a beginner. the theme of this website is the development of an online store with various products. everything went well until I had to create the first product (which, of course, also needs an image)
I don't get any errors from the compiler, I don't understand what the problem is. below is the specific piece of code for creating a new product.
after completing all the fields and adding an image click "save" and I receive this:
https://imgur.com/qwpnwNJ
below is also the part of the Create View for Products
<h2 class="text-info">Add New Product</h2>
<form asp-action="Create" method="post" enctype="multipart/form-data">
<div class="p-4 rounded border">
<div asp-validation-summary="ModelOnly" class="text-danger">
</div>
<h3>#ViewBag.message</h3>
<div class="form-group row">
<div class="col-2">
<label asp-for="Tag">Nume</label>
</div>
<div class="col-5">
<input asp-for="Tag" class="form-control" />
</div>
<span asp-validation-for="Tag" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Price"></label>
</div>
<div class="col-5">
<input asp-for="Price" class="form-control" />
</div>
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="GetImage("></label>
</div>
<div class="col-5">
<input asp-for="GetImage()" class="form-control" type="file" />
</div>
<span asp-validation-for="GetImage()" class="text-danger"></span>
</div>

How to use model data in a view?

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>

How to delete two entities in one click ASP.NET CORE MVC

I have in button delete which delete Ticket Entities and I add another entities call Discussion.
When user click on Details page it is load Discussion.
Now before I implement Discussion DeleteTicket method works fine, but now I add children and Ticket couldn't be deleted anymore.
My question is : Can I delete two entities at one time, or I need to delete first children entities and then parent ?
I try to google and try to find some soultion but unfortunettly anything which I find is not usefull for me.
DEMO
Here is my code :
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Linq;
using System.Security.Claims;
using VmSTicketing.DataAccess.Data;
using VmSTicketing.DataAccess.Repository.IRepository;
using VmSTicketing.Models;
using VmSTicketing.Models.Enum;
using VmSTicketing.Models.ViewModels;
using VmSTicketing.Utility;
namespace VmSTicketing.Areas.Manager.Controllers
{
[Area("Manager")]
[Authorize(Roles = SD.Role_Admin + "," + SD.Role_Manager)]
public class TicketController : Controller
{
private readonly IUnitOfWork _unitOfwork;
private readonly ApplicationDbContext _db;
public TicketController(IUnitOfWork unitOfwork, ApplicationDbContext db)
{
_unitOfwork = unitOfwork;
_db = db;
}
public IActionResult Index()
{
return View();
}
public IActionResult Upsert(int? Id)
{
TicketVM ticketVM = new TicketVM()
{
Ticket = new Ticket(),
TicketTypeList = _unitOfwork.TicketType.GetAll().Select(i => new SelectListItem
{
Text = i.Name,
Value = i.Id.ToString()
}),
ApplicationUser = new ApplicationUser(),
Client = new Client()
};
if (Id == null)
{
return View(ticketVM);
}
ticketVM.Ticket = _unitOfwork.Ticket.Get(Id.GetValueOrDefault());
if (ticketVM.Ticket == null)
{
NotFound();
}
return View(ticketVM);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Upsert(TicketVM ticketVM)
{
var users = _unitOfwork.ApplicationUser.GetAll(x => x.Id == x.UserName);
var userName = User.FindFirstValue(ClaimTypes.Email);
var user = HttpContext.User.Identity.Name;
if (ModelState.IsValid)
{
if (ticketVM.Ticket.Id == 0)
{
ticketVM.Ticket.ApplicationUser = _db.ApplicationUsers.FirstOrDefault(u => u.Email == userName);
ticketVM.Ticket.Status = TicketStatus.Otvoren.ToString();
_unitOfwork.Ticket.Add(ticketVM.Ticket);
}
//else
//{
// ticketVM.Ticket.ApplicationUser = _db.ApplicationUsers.FirstOrDefault(u => u.Email == userName);
// ticketVM.Ticket.Status = ((TicketStatus)Convert.ToInt32(ticketVM.Ticket.Status)).ToString();
// _unitOfwork.Ticket.Update(ticketVM.Ticket);
//}
_unitOfwork.Save();
return RedirectToAction(nameof(Index));
}
return View(ticketVM);
}
public IActionResult TicketStatusEdit(int ticketId)
{
var ticket = _unitOfwork.Ticket.Get(ticketId);
ticket.Status = ((TicketStatus)Convert.ToInt32(ticket.Status)).ToString();
_unitOfwork.Save();
return View();
}
public IActionResult Details(int? Id)
{
TicketVM ticketVM = new TicketVM()
{
Ticket = _unitOfwork.Ticket.Get(Id.GetValueOrDefault()),
};
if (Id == null)
{
return NotFound();
}
var ticketType = _unitOfwork.Ticket.GetAll(includeProperties: "TicketType,ApplicationUser");
ViewBag.discussion = _unitOfwork.Discussion.GetAll(d => d.TicketId == Id).OrderBy(d => d.Id).ToList();
return ticketVM.Ticket != null ? View(ticketVM) : NotFound();
}
[HttpPost]
public IActionResult SendDiscussion(int ticketId,string message)
{
var userName = User.FindFirstValue(ClaimTypes.Email);
var account = _db.ApplicationUsers.SingleOrDefault(a => a.UserName.Equals(userName));
var discussion = new Discussion();
discussion.DateAndTime = DateTime.Now;
discussion.Content = message;
discussion.TicketId = ticketId;
discussion.UserId = account.Id;
_unitOfwork.Discussion.Add(discussion);
_unitOfwork.Save();
return RedirectToAction("Details", new { id = ticketId});
}
#region API CALLS
[HttpGet]
public IActionResult GetByName(string name)
{
var obj = _unitOfwork.ApplicationUser.GetAll(x => x.Name == name);
//var obj = _unitOfwork.Ticket.GetAll(x => x.ApplicationUser.Name == name);
return Json(new { data = obj });
}
[HttpGet]
public IActionResult GetAll()
{
var username = User.FindFirst(ClaimTypes.Name).Value;
var account = _unitOfwork.ApplicationUser.GetFirstOrDefault(a => a.UserName.Equals(username));
var isAdministrator = User.IsInRole("Admin");
var obj = _unitOfwork.Ticket.GetAll(filter: x => (isAdministrator || x.UserId == account.FirstOrDefault().Id), includeProperties: "TicketType,ApplicationUser");
return Json(new { data = obj });
}
[HttpDelete]
[Authorize(Roles = SD.Role_Admin)]
public IActionResult Delete(int id)
{
var objFromDb = _unitOfwork.Ticket.Get(id);
if (objFromDb == null)
{
return Json(new { success = false, message = "Error while deleting" });
}
_unitOfwork.Ticket.Remove(objFromDb);
_unitOfwork.Save();
return Json(new { success = true, message = "Delete Successfull" });
}
#endregion
}
}
Details.cs
#model VmSTicketing.Models.ViewModels.TicketVM
#using VmSTicketing.Utility
#{
ViewData["Title"] = "Details";
Layout = "~/Views/Shared/AdminLTE/_Layout.cshtml";
}
<h2 class="text-info">Pregled tiketa</h2>
<div class="p-4 border rounded">
<div class="form-group row">
<div class="col-2">
<label>Vrsta tiketa</label>
</div>
<div class="col-5">
<input asp-for="Ticket.TicketType.Name" disabled class="form-control" />
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label>Opis</label>
</div>
<div class="col-5">
<textarea asp-for="Ticket.Description" disabled class="form-control"></textarea>
</div>
</div>
#if (User.IsInRole(SD.Role_Admin))
{
<input type="hidden" asp-for="Ticket.Id" />
<div class="form-group row">
<div class="col-2">
<label>User</label>
</div>
<div class="col-5">
<input asp-for="Ticket.ApplicationUser.Name" disabled class="form-control" />
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label>Datum i vrijeme slanja</label>
</div>
<div class="col-5">
<input asp-for="Ticket.DateAndTime" disabled class="form-control" />
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label>Status Tiketa</label>
</div>
<div class="col-5">
<select asp-for="#Model.Ticket.Status" asp-items="Html.GetEnumSelectList<VmSTicketing.Models.Enum.TicketStatus>()" class="form-control"></select>
</div>
</div>
}
<br />
<div class="form-group">
<a asp-action="Index" class="btn btn-success">Back to List</a>
</div>
</div>
<hr />
<div class="row">
<div class="col-md-12">
<div class="card card-primary direct-chat direct-chat-primary">
<div class="card-header">
<h3 class="card-title">Discussion</h3>
</div>
<div class="card-body">
<div class="direct-chat-messages">
#if (ViewBag.discussion != null)
{
#foreach (var discussion in ViewBag.discussion)
{
<div class="direct-chat-msg #(discussion.ApplicationUser.Role == "Admin" ? "": "right")">
<div class="direct-chat-infos clearfix">
<span class="direct-chat-name #(discussion.ApplicationUser.Role == "Admin" ? "float-right": "float-left")">#discussion.ApplicationUser.Name</span>
<span class="direct-chat-timestamp #(discussion.ApplicationUser.Role == "Admin" ? "float-left": "float-right")">#discussion.DateAndTime.ToString("dd/MM/yyyy HH:mm")</span>
</div>
<div class="direct-chat-text">
#discussion.Content
</div>
</div>
}
}
</div>
</div>
<div class="card-footer">
<form asp-controller="Ticket" asp-action="SendDiscussion" method="post">
<div class="input-group">
<input type="text" name="message" placeholder="Type Message ..." class="form-control">
<span class="input-group-append">
<button type="submit" class="btn btn-primary">Send</button>
</span>
</div>
<input type="hidden" name="ticketId" asp-for="Ticket.Id" />
</form>
</div>
</div>
</div>
</div>
Sorry for not adding enought source code I don't want to make this post only code, but If you need more source please let me know I will add later on.
if post is not so clean for you, please check DEMO and I hope it will be clear.
Cheers !
UPDATE
I add funtion to remove Discussion but It show me error message 405
[HttpDelete]
public IActionResult DeleteDiscussion(int id)
{
var discussion = new Discussion();
_unitOfwork.Discussion.Remove(discussion);
_unitOfwork.Save();
return View(discussion);
}
<a asp-area="Manager" asp-controller="Ticket" asp-action="DeleteDiscussion" class="btn btn-danger">Delete Discussion</a>
As #JamieD77 mentioned you need to delete child first, then delete the parent. Assuming your child entity is Discussion and parent is Ticket, you can do something like this. (if you don't have cascade delete implemented.)
[HttpDelete]
[Authorize(Roles = SD.Role_Admin)]
public IActionResult Delete(int id)
{
var objFromDb = _unitOfwork.Ticket.Get(id);
if (objFromDb == null)
{
return Json(new { success = false, message = "Record not found" });
}
if (objFromDb.Discussion != null) //if you have Discussion associated with Ticket delete that first.
{
try
{
_unitOfwork.Discussion.Remove(objFromDb.Discussion);
_unitOfwork.Save();
}
catch(Exception e)
{
return Json(new { success = false, message = "Error while deleting" });
}
}
try
{
_unitOfwork.Ticket.Remove(objFromDb);
_unitOfwork.Save();
}
catch(Exception e)
{
return Json(new { success = false, message = "Error while deleting" });
}
return Json(new { success = true, message = "Delete Successfull" });
}

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>
}

Categories

Resources