Submit to a new page and download a file - c#

I have code that allows users to create and edit records in a SQL database. This works fine. However, now I want it to output the SQL scripts for what is being done. I'm not sure how to do this. Here is my current code:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
<strong>ID:</strong>
<div class="col-md-10">
<p>
#Html.EditorFor(model => model.ID)
#Html.ValidationMessageFor(model => model.ID)
</div>
</div>
<br />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary">Submit <i class="fa fa-caret-right"></i></button>
</div>
</div>
</div>
}
public ActionResult Edit(int id)
{
using (var client = new XServiceClient())
{
X x = client.Find(id);
if (x == null)
{
return HttpNotFound();
}
return View(x);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(X x)
{
if (ModelState.IsValid)
{
using (var client = new XServiceClient())
{
client.Edit(x);
return Redirect("~/Home/Index");
}
}
return View(x);
}
I'm thinking in my controller I could do something like this:
using (var client = new XServiceClient())
{
var sessionID = Guid.NewGuid().ToString("N");
var filename = String.Format("Session-{0}.sql", sessionID);
var sqlString = "Update SQL String Stuff";
File(System.Text.UTF8Encoding.UTF8.GetBytes(sqlString), "text/plain", filename);
client.Edit(x);
return Redirect("~/Home/Index");
}
Most systems I have seen recommend a return on that File line. However, that won't work with the rest of the program.
How can I get my submit button to submit the data to the server and also download a file to the user?

Related

Authorization: users able to edit their own details when loggedin

I have an application where I want Volunteers to be able to help with a Ceremony.
I would like them to be log in and click a button, this brings them to a page where their details appear and a list of Ceremonies they can apply for. I have that page working but I have no way of getting the current user logged in.
Also, for clarification: I have a Volunteer entity which holds the data and then a separate user entity. The username for a Volunteer is the same as their user entity.
I want to:
Compare the Username to the Volunteer Username and get the
VolunteerId.
2.This will then be used to edit/join a ceremony for that particular volunteer.
Here's my Volunteer Controller methods:
// GET:
public ActionResult VolunteerCeremony(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
string userName = string.Empty;
var getVolunteerId = (from u in db.Volunteers
where WebSecurity.CurrentUserName == u.Username
select u.VolunteerId).SingleOrDefault();
Volunteer v = (Volunteer)(from k in db.Volunteers
where getVolunteerId == k.VolunteerId
select k).SingleOrDefault();
if (v == null)
{
return HttpNotFound();
}
PopulateAssignedCeremonyData(v);
return View(v);
}
// GET:
public ActionResult VolunteerHub()
{
return View();
}
// POST: /Player/VolunteerCeremony/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult VolunteerCeremony(int? id, string[] selectedOptions)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var getVolunteerId = (from u in db.Volunteers
where WebSecurity.CurrentUserName == u.Username
select u.VolunteerId).SingleOrDefault();
var v = (Volunteer)(from k in db.Volunteers
where getVolunteerId == k.VolunteerId
select k).SingleOrDefault();
try
{
UpdateVolunteerCeremonies(selectedOptions, v);
db.Entry(v).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateAssignedCeremonyData(v);
return View(v);
}
And then my Razor pages, the first which I want the user to click a link to bring them to the edit/join ceremony page:
#model PIMS.Entities.Volunteer
#{
ViewBag.Title = "VolunteerHub";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<li>#Html.ActionLink("Join Ceremony", "VolunteerCeremony", "Volunteers", null, new { id = #model.VolunteerId })</li>
This gives me an error on the new { id = #model.VolunteerId }
Then the page which I want to get to:
#model PIMS.Entities.Volunteer
#using Microsoft.AspNet.Identity
#{
ViewBag.Title = "VolunteerCeremony";
}
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<h2>Apply for Ceremony</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.VolunteerId)
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.VolunteerRole, "Volunteer Role", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.VolunteerRole, new { #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.VolunteerRole)
</div>
</div>
</div>
<div class="row">
<div class="col-md-2"> </div>
<div class="form-group col-md-4">
<label class="control-label">Assigned Ceremonies</label>
#Html.ListBox("selectedOptions", (MultiSelectList)ViewBag.SelectedCeremonies, new { #class = "form-control" })
</div>
<div class="form-group col-md-1" style="text-align:center">
<div class="form-group">
<button type="button" id="btnRight" class="btn btn-warning btn-lg">
<span class="glyphicon glyphicon-arrow-right"></span>
</button>
</div>
<div class="form-group">
<button type="button" id="btnLeft" class="btn btn-success btn-lg">
<span class="glyphicon glyphicon-arrow-left"></span>
</button>
<div></div>
</div>
</div>
<div class="form-group col-md-4">
<label class="control-label">Available Ceremonies</label>
#Html.ListBox("availOptions", (MultiSelectList)ViewBag.AvailCeremonies, new { #class = "form-control" })
</div>
<input type="submit" id="btnSubmit" value="Save" class="btn btn-default" />
</div>
<div style="text-align:center;">
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/multisel")
}
Does anyone have any experience with this as it sort of key to my application!
in mvc there is something called session variables, its just like app.config variables, you declare them like this in the controller
Session["Volunteer"] = "volunteer1";
once declared they will remain declared for the entire session.
then you write code for the logoff to reset the Session variable to something that your code handles as no-one logged in or just null.

Entity edit doesn't save in ASP.NET MVC Core

I got a form for editing my user info:
<form asp-action="EditUser" asp-route-returnurl="#ViewData["ReturnUrl"]">
<div class="form-horizontal">
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="User.Id" />
<div class="form-group">
<label asp-for="User.Name" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="User.Name" class="form-control" />
<span asp-validation-for="User.Name" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="User.Surname" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="User.Surname" class="form-control" />
<span asp-validation-for="User.Surname" class="text-danger"></span>
</div>
</div>
</div>
</form>
Here is my MVC action:
[HttpPost, ActionName("EditUser")]
[Authorize(Roles = Roles.Root + "," + Roles.Manager)]
public async Task<IActionResult> Edit(string id, string returnUrl = null)
{
if (ModelState.IsValid)
{
try
{
var studentToUpdate = await _dbContext.Users.SingleOrDefaultAsync(s => s.Id == id);
// Try to update user from DB by edited values from form
if (await TryUpdateModelAsync<ApplicationUser>(studentToUpdate, "User.",
s => s.Surname, u => u.Name))
_dbContext.SaveChanges();
return Redirect(returnUrl);
}
}
}
In debug I could see that in Request.Form property there are new right values, but DB entity hasnt updated. How could I fix that?
We normally use a view model as a parameter, and bind the posted value to it. Then update the record base on it.
[HttpPost, ActionName("EditUser")]
[Authorize(Roles = Roles.Root + "," + Roles.Manager)]
public async Task<IActionResult> Edit(string id, EditViewModel model,
string returnUrl = null)
{
if (ModelState.IsValid)
{
var studentToUpdate = await _dbContext.Users.SingleOrDefaultAsync(s => s.Id == id);
if (studentToUpdate != null)
{
studentToUpdate.Surname = model.Surname;
... Other properties
await _dbContext.SaveChangesAsync();
}
return Redirect(returnUrl);
}
return View(model);
}

Multiple TempData variables passed to same action

I'm creating ASP.NET web application using MVC and Entity Framework. I have two different success messages I am passing to an index action for when a user clocks in or clocks out. The success message will print correctly when a user clocks in, but will not when a user clocks out for some reason.
The actions are very similar and I used all of the same conventions so I can't figure out why one would print and another would not. I've tried debugging and there are no red flags and everything updates in the database like it should. Is it not possible to pass multiple TempData variables to the same action?
Here is the relevant code:
Controller
// GET: TimeClocks
public ActionResult Index()
{
ViewBag.ClockInSuccess = TempData["ClockInSuccess"];
ViewBag.ClockOutSuccess = TempData["ClockOutSuccess"];
return View();
}
[HttpPost]
public ActionResult ClockIn(TimeClock timeClock)
{
if(db.TimeClocks.ToList().Count == 1)
{
ModelState.AddModelError("ExistsError", "You already clocked in at" + timeClock.ClockIn);
}
string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
timeClock.ApplicationUser = currentUser;
timeClock.ClockIn = DateTime.Now;
if (ModelState.IsValid)
{
db.TimeClocks.RemoveRange(db.TimeClocks.ToList());
db.TimeClocks.Add(timeClock);
db.SaveChanges();
TempData["ClockInSuccess"] = "You clocked in successfully at " + timeClock.ClockIn;
return RedirectToAction("Index");
}
return RedirectToAction("Index", timeClock);
}
[HttpPost]
public ActionResult ClockOut(TimeClock timeClock)
{
timeClock = db.TimeClocks.FirstOrDefault();
if(timeClock.ClockIn == null)
{
ModelState.AddModelError("NullError", "You must clock in before you can clock out.");
return RedirectToAction("Index");
}
timeClock.ClockOut = DateTime.Now;
if (ModelState.IsValid)
{
db.Entry(timeClock).State = EntityState.Modified;
db.SaveChanges();
TempData["ClockOutSuccess"] = "You clocked out successfully at " + timeClock.ClockOut;
return RedirectToAction("Index");
}
return RedirectToAction("Index", timeClock);
}``
View
#model FinalProject.Models.TimeClock
#{
ViewBag.Title = "Create";
}
<h2>Employee Time Clock</h2>
#using (Html.BeginForm("ClockIn", "TimeClocks"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Clock In" class="btn btn-lg" />
</div>
</div>
</div>
}
#using (Html.BeginForm("ClockOut", "TimeClocks"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Clock Out" class="btn btn-lg" />
</div>
</div>
</div>
}
#{
if (#ViewBag.ClockInSuccess != "")
{
<p class="alert-success">#ViewBag.ClockInSuccess</p>
}
else if (#ViewBag.ClockOutSuccess != "")
{
<p class="alert-success">#ViewBag.ClockOutSuccess</p>
}
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
TempData is lost once you read it so you need to do a Peek or a Keep:
ViewBag.ClockInSuccess = TempData.Peek("ClockInSuccess");
ViewBag.ClockOutSuccess = TempData.Peek("ClockOutSuccess");
http://www.codeproject.com/Articles/818493/MVC-Tempdata-Peek-and-Keep-confusion

Mvc ViewBag - Cannot convert null to 'bool' because it is a non-nullable value type

I want to set a bool to true in the controller when producing a certain view and then alter the header of the view accordingly. This should be dead simple but instead Im getting:
Cannot perform runtime binding on a null reference Exception Details:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform
runtime binding on a null reference
All I'm doing is in controller:
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.IsRegistration = true;
return View();
}
and then in view:
#if (ViewBag.IsRegistration)
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
but it fails on:
#if (ViewBag.IsRegistration)
UPDATE
Relevant Controller Code:
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.IsRegistration = "true";
return View();
}
The register view:
#model Mvc.Models.RegisterViewModel
#{
Layout = "~/Views/Shared/_AccountLayout.cshtml";
ViewBag.Title = "Register";
}
<hgroup class="title">
<h1>#ViewBag.Title.</h1>
</hgroup>
<div class="row">
<div class="col-lg-6">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset class="form-horizontal">
<legend>Create a new account.</legend>
<div class="control-group">
#Html.LabelFor(m => m.UserName, new { #class = "control-label" })
<div class="controls">
#Html.TextBoxFor(m => m.UserName)
</div>
</div>
<div class="control-group">
#Html.LabelFor(m => m.Password, new { #class = "control-label" })
<div class="controls">
#Html.PasswordFor(m => m.Password)
</div>
</div>
<div class="control-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "control-label" })
<div class="controls">
#Html.PasswordFor(m => m.ConfirmPassword)
</div>
</div>
<div class="form-actions no-color">
<input type="submit" value="Register" class="btn" />
</div>
</fieldset>
}
</div>
<div class="col-lg-6"></div>
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList", new { ReturnUrl = ViewBag.ReturnUrl })
</section>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The ExternalLoginsList partial:
#using Glimpse.Core.Extensions
#using Microsoft.Owin.Security
#model ICollection<AuthenticationDescription>
#if (Model.Count == 0)
{
<div class="message-info">
<p>There are no external authentication services configured</p>
</div>
}
else
{
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
<fieldset id="socialLoginList">
#if (!string.IsNullOrEmpty(ViewBag.IsRegistration))
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
<p>
#foreach (AuthenticationDescription p in Model) {
<button type="submit" class="btn" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType" title="Log in using your #p.Caption account">#p.AuthenticationType</button>
}
</p>
</fieldset>
}
}
Try:
#if (ViewBag.IsRegistration == true)
I know this is an old question, but I think I have an elegant answer, so in case anyone reads this after searching, here is mine:
#if (ViewBag.IsRegistration ?? false)
Try this:
Replace the line in your controller:
ViewBag.IsRegistration = true;
with
ViewBag.IsRegistration = new bool?(true);
and replace the line in your view:
#if (ViewBag.IsRegistration)
with
#if ((ViewBag.IsRegistration as bool?).Value)
Effectively you are putting a nullable bool in the ViewBag and then unwrapping it.
Simply check for null before checking for true:
if (ViewBag.IsRegistration != null && ViewBag.IsRegistration)
Try TempData instead of ViewBag.
Change your code from
Controller
ViewBag.IsRegistration=true;
to
TempData["IsReg"]=true;
and in View
#if((bool)TempData["IsReg"])
It seems that you are using the value in child partial view and you are adding the data in parent action.The values in viewbag cannot pass out data from one action to anothers action's view. While TempData use session it can be used to pass data to one action to another actions view.
Ok so as per Floods suggestion in comments, I need to pass the arguments around. The ViewBag from the parent View does not flow through to partial views.
So in the code for the Register View I needed to change from
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList", new {ReturnUrl = ViewBag.ReturnUrl})
</section>
to
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList",
new {ReturnUrl = ViewBag.ReturnUrl,
IsRegistering = #ViewBag.IsRegistering })
</section>
Then go into my account controller and change from:
[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}
to
[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl, string isRegistering) {
ViewBag.IsRegistering = (isRegistering.ToLower() == "true");
ViewBag.ReturnUrl = returnUrl;
return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}
Then in the ExternalLogins I can just:
#if (ViewBag.IsRegistering)
as necessary.
So Im effectively passing the IsRegistering bool from controller to main view then back up to action method on controller then into ViewBag which allow me to access the bool in the child partial view.
Many thanks.
Booleans in Viewbag are always tricky. Try this instead
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.Registration = "x";//x or whatever
return View();
}
#if (!String.IsNullorEmpty(ViewBag.Registration))
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
Maybe so:
#if ((ViewBag.IsRegistration != null) && (ViewBag.IsRegistration is bool) && (bool)ViewBag.IsRegistration)
{
}

Image not saving when updated in view

While developing an ASP.NET MVC 4 application I ran into a problem updating a saved image.
Basically when the user selects the edit tab, their re-directed to the content they previously entered.
One such item of that content is an image, and when in the edit menu they can choose to replace the existing image.
I have the other content updating correctly but the image remains the same, when I place a breakpoint on the "edit" ActionResult, it show the image value for the passing model as null? newsArticle.ArticleImage = Null
FYI - Image is saved as a byte array.
Am I missing something ?
Controller....
[HttpPost]
public ActionResult Edit(NewsArticle newsArticle, int id, HttpPostedFileBase Article)
{
try
{
if (ModelState.IsValid)
{
NewsArticle savedArticle= _newsArticle.Get(id);
savedArticle.Body = newsArticle.Body;
savedArticle.Title = newsArticle.Title;
if (newsArticle.ArticleImage == null)
{
newsArticle.ArticleImage = savedArticle.ArticleImage;
}
else
{
using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
{
newsArticle.ArticleImage = binaryReader.ReadBytes(Request.Files[0].ContentLength);
}
savedArticle.ArticleImage = newsArticle.ArticleImage;
}
if (newsArticle.ImageName == null)
{
newsArticle.ImageName = savedArticle.ImageName;
}
else
{
string imgeName = Path.GetFileName(Article.FileName);
savedArticle.ImageName = imgeName;
}
_uow.SaveChanges();
return RedirectToAction("Index");
}
}
catch (System.Data.DataException)
{
//Log th error(add a variable name after DataExpection)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(newsArticle);
}
View..........
#using (Html.BeginForm("Edit", "Admin", FormMethod.Post, new { enctype = "multipart/form-data", #class = "form-horizontal", id = "newsEditForm" }))
{
#Html.ValidationSummary()
#Html.HiddenFor(model => model.ID)
<div class="control-group">
<label class="control-label">Posted on :</label>
<div class="controls">
<span class="text">#Model.DateCreated.Value.ToShortDateString()</span>
#*#Html.LabelFor(n => n.DateCreated)*#
</div>
</div>
<div class="control-group">
<label class="control-label">#Html.LabelFor(n => n.Title)</label>
<div class="controls">
#Html.TextBoxFor(n => n.Title, new { #class = "span4 m-wrap", rows = 1 })
</div>
</div>
<div class="control-group">
<label class="control-label">#Html.LabelFor(n => n.Body)</label>
<div class="controls">
#Html.TextAreaFor(n => n.Body, new { #class = "span12 ckeditor m-wrap", rows = 4 })
</div>
</div>
<div class="control-group">
<label class="controls">#Html.DisplayTextFor(model => model.ImageName)</label>
<div class="span4 blog-img blog-tag-data">
<div class="editor-field">
<input type="file" name="Article" id="ArticleImage" />
</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn green" id="submitnews"><i class="icon-ok"></i>Submit</button>
#Html.ActionLink("Cancel", "ArticleList", "Admin", null, new { #class = "btn blue" })
#*<button type="button" class="btn blue" onclick="location.href='ArticleList','Admin'">Cancel</button>*#
</div>
}

Categories