How to render input elements inside form elements - asp.net

Antaris RazorEngine v3.9.3 is used in ASP.NET MVC4 controller to create form element.
In result html input elements are rendered outside form element.
For example
#using (Html.BeginForm("Test", "Upload"))
{
<input type="file" />
<input type="submit"/>
}
produces
<form action="/Upload/Test" method="post"></form>
<input type="file" />
<input type="submit"/>
while correct result should be
<form action="/Upload/Test" method="post">
<input type="file" />
<input type="submit"/>
</form>
RenderScript returns only input elements. <form action="/Upload/Test" method="post"> is written to output directly. It looks like BeginForm() writes directly to view and Razorengine does not capture its output.
How to fix this ?
View:
#Model.RenderScript()
Model:
public IHtmlString RenderScript() {
var config = new TemplateServiceConfiguration();
config.BaseTemplateType = typeof(HtmlTemplateBase<>);
config.Namespaces = new HashSet<string>(new string[] {
"System",
"System.Collections",
"System.Collections.Generic",
"System.Globalization",
"System.Linq",
"System.Web",
"System.Web.Mvc",
"System.Web.Mvc.Html"
});
razor = RazorEngineService.Create(config);
// In real application colModel is retrieved from database
var colModel=#"
#using (Html.BeginForm(""Test"", ""Upload""))
{
<input type='file' />
<input type='submit'/>
}
";
string res = razor.RunCompile(colmodel, colmodel, typeof(object), new object());
return MvcHtmlString.Create(res);
}
Template base class:
using RazorEngine.Templating;
using RazorEngine.Text;
using System;
using System.IO;
using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;
public class HtmlTemplateBase<T> : TemplateBase<T>, IViewDataContainer
{
// http://stackoverflow.com/questions/8561164/razorengine-issues-with-html
HtmlHelper<T> helper = null;
ViewDataDictionary viewdata = null;
public HtmlHelper<T> Html
{
get
{
// https://github.com/Antaris/RazorEngine/issues/150
if (helper == null)
{
var p = WebPageContext.Current;
var wvp = p.Page as WebViewPage;
var context = wvp != null ? wvp.ViewContext : null;
context.Writer = this.CurrentWriter;
helper = new HtmlHelper<T>(context, this);
}
return helper;
}
}
public ViewDataDictionary ViewData
{
get
{
if (viewdata == null)
{
viewdata = new ViewDataDictionary();
viewdata.TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = string.Empty };
if (this.Model != null)
{
viewdata.Model = Model;
}
}
return viewdata;
}
set
{
viewdata = value;
}
}
public override void WriteTo(TextWriter writer, object value)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (value == null) return;
//try to cast to RazorEngine IEncodedString
var encodedString = value as IEncodedString;
if (encodedString != null)
{
writer.Write(encodedString);
}
else
{
var htmlString = value as IHtmlString;
if (htmlString != null) writer.Write(htmlString.ToHtmlString());
else
{
encodedString = TemplateService.EncodedStringFactory.CreateEncodedString(value);
writer.Write(encodedString);
}
}
}
}
Posted also in https://github.com/Antaris/RazorEngine/issues/443

Related

Mvc Reading Excel and Updating into Table But Need to Display as Well

I am reading the Excel file and comparing it with the tblsites if SiteCode exists it will update else it'll add the site, I just wanted to return sitecode which are updated and those which are newly added in order to display to the user.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ExceltoDB.Models;
using ClosedXML.Excel;
using System.Data;
using System.IO;
namespace ExceltoDB.Controllers
{
public class BulkController : Controller
{
// GET: Bulk
public ActionResult Index()
{
return View();
}
public ActionResult Create(HttpPostedFileBase FileUpload)
{
if (FileUpload != null && FileUpload.ContentLength > 0 && System.IO.Path.GetExtension(FileUpload.FileName).ToLower() == ".xlsx")
{
string filename = Path.GetFileNameWithoutExtension(FileUpload.FileName);
string extension = Path.GetExtension(FileUpload.FileName);
filename = filename + DateTime.Now.ToString("yymmssfff") + extension;
string targetpath = Server.MapPath("~/Doc/");
string path = targetpath + filename;
FileUpload.SaveAs(path);
using (XLWorkbook workbook = new XLWorkbook(path))
{
using (var context = new Inventory_ManagementEntities())
{
var sitesList = context.tblSites.ToList();
IXLWorksheet worksheet = workbook.Worksheet(1);
List<tblSite> newSitesList = new List<tblSite>();
var lastUsedRow = worksheet.LastRowUsed().RowNumber();
for (int i = 2; i <= lastUsedRow; i++)
{
var SiteCode = worksheet.Row(i).Cell(1).Value.ToString().Trim();
var site = sitesList.Where(x => x.SiteCode == SiteCode).FirstOrDefault();
var ApprovalStatus = worksheet.Row(i).Cell("B").Value.ToString().Trim();
var SiteStatus = worksheet.Row(i).Cell("C").Value.ToString().Trim();
if (site != null)
{
site.ApprovalStatus = ApprovalStatus;
site.SiteStatus = SiteStatus;
context.SaveChanges();
}
else
{
newSitesList.Add(new tblSite
{
SiteCode = worksheet.Row(i).Cell("A").Value.ToString().Trim(),
ApprovalStatus = worksheet.Row(i).Cell("B").Value.ToString().Trim(),
SiteStatus = worksheet.Row(i).Cell("C").Value.ToString().Trim(),
});
}
}
if (newSitesList.Count > 0)
{
context.tblSites.AddRange(newSitesList);
context.SaveChanges();
}
if ((System.IO.File.Exists(path)))
{
System.IO.File.Delete(path);
}
}
}
}
else
{
}
return View();
}
My View is Simple where i am getting the excel file from the user.
#model IEnumerable<ExceltoDB.Models.tblSite>
#{
ViewBag.Title = "Bulk";
}
#using (Html.BeginForm("Create", "Bulk", FormMethod.Post, new{
enctype = "multipart/form-data" }))
{
<div>
<label>Upload File:</label>
<input type="file" id="FileUpload" name="FileUpload" />
<input type="submit" value="Upload File" />
</div>
}

Updating column in ASP.NET mvc 5 creates new row

I'm following this tutorial to create a modified version of a blog. In this case, the "posts" are the same things as "projects," the "tags" are called "technologies," and the comments are all the same. In this case, the create new post/project function also should be able to update existing posts/projects. When I click submit, however, editing an old post, it simply creates a new one.
Here is my controller:
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Update(int? p, string title, string shortDescription, string longDescription, DateTime dateTime, string technologies)
{
Project project = GetProject(p);
if (!User.IsInRole("ChapterAdvisor") || !(User.Identity.GetFirstName() + " " + User.Identity.GetLastName()).Equals(project.ProjectLeader))
{
RedirectToAction("Index");
}
project.Title = title;
project.ShortDescription = shortDescription;
project.LongDescription = longDescription;
project.TimeCreated = dateTime;
project.ProjectLeader = User.Identity.GetFirstName() + " " + User.Identity.GetLastName();
project.Technologies.Clear();
technologies = technologies ?? string.Empty;
string[] technologyNames = technologies.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
foreach (string technologyName in technologyNames)
{
project.Technologies.Add(GetTechnology(technologyName));
}
if (!p.HasValue)
{
model.Projects.Add(project);
}
try
{
model.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
// raise a new exception nesting
// the current instance as InnerException
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
return RedirectToAction("Details", new { p = project.Id });
}
public ActionResult Edit(int? p)
{
Project project = GetProject(p);
StringBuilder technologyList = new StringBuilder();
foreach (Technology technology in project.Technologies)
{
technologyList.AppendFormat("{0} ", technology.Name);
}
ViewBag.Technologies = technologyList.ToString();
return View(project);
}
private Technology GetTechnology(string technologyName)
{
return model.Technologies.Where(x => x.Name == technologyName).FirstOrDefault() ?? new Technology() { Name = technologyName };
}
private Project GetProject(int? id) => id.HasValue ? model.Projects.Where(x => x.Id == id).First() : new Project() { Id = -1 };
And this is my view:
<form action="#Href("~/Projects/Update")" method="post" id="postForm">
#Html.AntiForgeryToken()
#if (Model.Id != -1)
{
<input type="hidden" value="#Model.Id" />
}
#{ DateTime dateTime = Model.TimeCreated.Year > 2000 ? Model.TimeCreated : DateTime.Now; }
<input type="text" name="dateTime" value="#dateTime" /> Date<br />
<input type="text" name="title" value="#Model.Title" /> Project Name<br />
#Html.DropDownListFor(m => m.Technologies, new SelectList(new List<Object> { new { value = "Animation", text = "Animation" }, new { value = "Robotics", text = "Robotics" }, new { value = "Architecture", text = "Architecture" }, new { value = "CAD", text = "CAD" }, new { value = "Websites", text = "Websites" }, new { value = "Games", text = "Games" }, new { value = "Biotechnology", text = "Biotechnology" }, new { value = "Club", text = "Club" }, new { value = "Other", text = "Other" } }, "value", "text"), new { #style = "border: 1px solid #e8e8e8;padding: 0.5em 1.07em 0.5em;background: #f5f5f5;font-size: 0.875rem;border-radius: 5px;width: 100%;line-height: 1.43;min-height: 3.5em;" })
<textarea name="shortDescription" rows="5" cols="80">#Model.ShortDescription</textarea><br />
<textarea name="longDescription" rows="10" cols="80">#Model.LongDescription</textarea><br />
<input type="submit" name="submit" value="Save Changes" />
</form>
Any ideas why it is creating a new "project" instead of updating the one defined by the variable passed in the url?
Every post from that form is being treated as a "new" record because it doesn't contain the ID from an existing record. So the logic always assumes it's new.
This is because the hidden input isn't included in the POST data because it has no name:
<input type="hidden" value="#Model.Id" />
It looks like your action expects the ID value to be called "p":
<input type="hidden" name="p" value="#Model.Id" />

System.NotSupportedException was unhandled by user code, LINQ to Entities does not recognize the method

I am new in MVC asp.net i am developing a project where i want to add floors sequence wise. Want to start sequence from 0.
Message=LINQ to Entities does not recognize the method 'NTB.Floor LastOrDefault[Floor](System.Linq.IQueryable1[NTB.Floor], System.Linq.Expressions.Expression1[System.Func`2[NTB.Floor,System.Boolean]])' method, and this method cannot be translated into a store expression.
Controller:
public ActionResult Create(int id)
{
var cfloorno = 0;
//if (bid > 0)
//{
var lastfloor = db.Floors.Last(x => x.BuildingId == id);
if (lastfloor != null)
{
cfloorno = lastfloor.FloorNo.GetValueOrDefault() + 1;
}
//}
var building = db.Buildings.ToList();
ViewBag.Building = building;
var type = db.FloorTypes.ToList();
ViewBag.Type = type;
ViewBag.CurrentFloor = cfloorno;
ViewBag.buildingid = id;
return View();
}
[HttpPost]
public ActionResult Create(Floor f)
{
using (db)
{
db.Floors.Add(f);
db.SaveChanges();
}
return RedirectToAction("List");
}
View:
<input type="hidden" name="BuildingId" value="#ViewBag.buildingid" />
<div class="row">
<label class="col-sm-2 control-label">Floor #</label>
<div class="col-sm-10">
<input class="form-control" name="FloorNo" value="#ViewBag.CurrentFloor" disabled type="number">
#Html.ValidationMessageFor(model => model.FloorNo)
</div>
</div>

Asp.net MVC, Pass Array to Controller From View Without Using Ajax

I am Using asp.net mvc 5. I want to pass array of string from view to controller without using Ajax. Can Anyone help?
This is the controller, value is to be gotten in packagelist[]
public ActionResult Create(Business business, string loc, string serv, string[] packagelist)
{
try
{
if (ModelState.IsValid)
{
var a = locationIds;
business.ServiceId = db.Services.Where(x => x.Title ==serv).Select(x => x.Id).SingleOrDefault();
business.LocationId = db.Locations.Where(x => (x.Title + " (" + x.State + "), " + x.PostalCode)==loc).Select(x => x.Id).SingleOrDefault();
db.Businesses.Add(business);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
foreach(var error in ModelState.Values)
{
foreach(var er in error.Errors)
ModelState.AddModelError("", er.Exception.ToString());
}
}
ViewData["Packages"] = db.BusinessPackages.Select(x => new SelectListItem
{
Text = x.Package,
});
return View(business);
}
catch(Exception ex)
{
ModelState.AddModelError("", ex);
return View(business);
}
}
Have created an hidden input on view
<input type="hidden" name="packagelist" id="packagelist" value="" />
Then set the value of this hidden field via this function
$("#theform").submit(function (e) {
e.preventDefault();
var locdiv=$("#maindiv");
var locations = locdiv.children();
var loc = [];
for (var i = 0; i < locations.length; i++)
{
loc.push(locations.eq(i).text());
}
// SaveLocations(loc);
$("#packagelist").val(loc);
$("#theform").submit();
Now main problem is that when I set value of the input via Jquery and submit it to the controller, controller is considering the array of values as single value.
To receive an array as param in controller, your inputs need specific naming
<input type="hidden" name="packagelist[0]" id="packagelist_0_" value="" />
<input type="hidden" name="packagelist[1]" id="packagelist_1_" value="" />
<input type="hidden" name="packagelist[2]" id="packagelist_2_" value="" />
...
<input type="hidden" name="packagelist[x]" id="packagelist_x_" value="" />
I think you can use cookies.
In JS,
document.cookie = "CookiesName=" + value + "; " + "365;path=/";
In Controller,
var data = Request.Cookies["CookiesName"]

How to upload file with web-api

Client side code:
<form action="api/MyAPI" method="post" enctype="multipart/form-data">
<label for="somefile">File</label> <input name="somefile" type="file" />
<input type="submit" value="Submit" />
</form>
And how to process upload file with mvc web-api,have some sample code?
HTML Code:
<form action="api/MyAPI" method="post" enctype="multipart/form-data">
<label for="somefile">File</label>
<input name="somefile" type="file" />
<input type="submit" value="Submit" />
</form>
Controller
// POST api/MyAPI
public HttpResponseMessage Post()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.AllKeys[0] == "image")
{
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/Images/" + postedFile.FileName);
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
try below link
this link use for me hopefully it will work you
http://www.asp.net/web-api/overview/advanced/sending-html-form-data,-part-2
You can use ApiMultipartFormFormmatter to upload file to web api 2.
By using this library, you can define a view model to get parameters submitted from client-side. Such as:
public class UploadFileViewModel
{
public HttpFile Somefile{get;set;}
}
And use it in your Api controller like this:
public IHttpActionResult Upload(UploadFileViewModel info)
{
if (info == null)
{
info = new UploadFileViewModel();
Validate(info);
}
if (!ModelState.IsValid)
return BadRequest(ModelState);
return Ok();
}
Nested objects can be parsed by this library.

Resources