MVC 5 refresh partial view with information from post - asp.net

Hello I have this puzzle and i would like to share and see if my solution is plausible and possibly get some help.
Basically I have a view called "Create".
Now i click "Escolher Ficheiro" (means "Choose File"), I choose the wanted file and click fill.
So far so good, my file reaches the POST method and its ok at this point.
You can see in the image below that I extract that number from the file and the button "Create" its shown.
However as you can see my "Choose File" input gets null "Nenhum fic..."(means no file selected)
This happens because I return the View Create and it refreshes my whole page.
The thing is that I need to go trhough a POST action on my Controller, so i can read that Prop1.
For obvious security reasons I cannot set a file by default, so I have tried to have some partial views and returning only that partial, but there is something im missing completly. Is there a way of refreshing the "bottom part of the view trhough ajax but going trhough the action on the controller at the same time?
Here is my controller Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "XL2XMLProcID,SourceXLFiles,Prop1,Prop2,TargetXMLFile,State")] XL2XMLProc xL2XMLProc, HttpPostedFileBase postedFile, string submitButton)
{
if (ModelState.IsValid)
{
if (postedFile != null)
{
// fetch the date from the file
var h = new XLHelper();
var v = h.Fetch("nrContaACreditarRC", postedFile.FileName, #"C:\somefolder\somefolder\somefolder\ExcelSamples\");
if (submitButton == "Create")
{
TestZipAndUpload(v);
}
else
{
// extract postedFile data to show
xL2XMLProc.Prop1 = v;
ViewBag.comingFromFill = true;
return View(ActionName.Create.ToString(), xL2XMLProc);
}
}
else
{
// posted file is null, throw error.
return View();
}
return RedirectToAction(ActionName.Index.ToString());
}
return View(xL2XMLProc);
}
Thank you in advance.

Related

Editing details on a page with a picture

I have a page with a picture and few other fields . Uploading picture works fine.If user wants to edit and put a different picture, that works fine too. The problem occurs when user edit a different field (other than the image field) in the record . After saving , the image disappears.
Here is my controller
public ActionResult Edit([Bind(Include = "GlobalMaterialId,Length,Picture")] MetalStock metalStock, HttpPostedFileBase ImageFile)
{
if (ModelState.IsValid)
{
if (ImageFile != null)
{
string pic = System.IO.Path.GetFileName(ImageFile.FileName);
metalStock.ImagePath = pic;
using (MemoryStream ms = new MemoryStream())
{
ImageFile.InputStream.CopyTo(ms);
metalStock.Picture = ms.GetBuffer();
}
}
m_db.Entry(metalStock).State = EntityState.Modified;
m_db.SaveChanges();
return RedirectToAction("Index");
}
return View(metalStock);
}
here is the image uploading bit of the view
<input name="ImageFile" type='file' / >
I understand that when I edit a field and save, ImageFile that is passed to the controller is empty and that creates the problem. I tried few other things such as trying to get the picture from the record and reassigning it to the object etc. Non of them worked. Please help.
I would guess your controller dies because it looks for a HttpPostedFile and does not get one.
You can either make it nullable in the declaration of your action
public ActionResult Edit([Bind(Include = "GlobalMaterialId,Length,Picture")] MetalStock metalStock, HttpPostedFileBase ImageFile = null)
or don't declare it in the controller at all and pick it up from the Request:
var Image = Request.Files["ImageFile"]
You could store your existing image file in a hidden field as a base64 string and in your post action check to see if the HttpPostedFileBase is null (they haven't selected a different image). If it is, convert your base64 string back to a byte array and assign it to your metalStock.Picture property.
This is how I've handled this scenario in the past. You will need to create another property on your viewmodel to hold this base64 string. This is beneficial assuming your view is not bound directly to your entity, but a viewmodel instead.

Unable to download PDF file with Rotativa in MVC4

I am using Rotativa to turn a Razor view into a PDF.
The PDF file is not downloading.
I can see it in Fiddler but the browser is not prompting for download - I have tried this with both IE and Chrome.
I also tried to download the file to a physical path using the solution in this question here. but that didn't work either because of the system couldn't access the folder (Access Denied).
Here is my code:
public ActionResult Index()
{
var model = new CustomerDashboardVM();
return View("Index", model);
}
public ActionResult print(int voucherID)
{
var pdf = new ActionAsPdf("Index", new { voucherID}) { FileName = "testInvoice.pdf", PageSize = Rotativa.Options.Size.A4};
// RotativaHelper.SaveHttpResponseAsFile("http://localhost:65425/BlankDashboard", Server.MapPath("~\\PdfDownloads"));
return pdf;
}
I wonder why is this happening - I click the button, it calls the print ActionResult method - no error messages (I wrapped this in a try and catch block). I have tried this on a colleague PC and it was the same issue!
Many thanks.
The issue was that I was calling the ActionResult print() method on a button click event through an Ajax post. This apparently doesn't work.
It should work if you replace the button with a link, which has the print() mehtod in its URL; i.e., just the way mvc links work..
Okay, i got your mistake. You have not passed parameter name voucherID in Index method.
So now your code look like this:
public ActionResult Index(int voucherID) // Here you have to pass parameter
{
var model = new CustomerDashboardVM(voucherID);
return View("Index", model);
}
and Print() method look like this -
public ActionResult Print(int voucherID)
{
return new ActionAsPdf(
"Index",
new { voucherID = voucherID })
{
FileName = "testInvoice.pdf",
PageSize = Rotativa.Options.Size.A4
};
}

How to handle a POST request to a URL that contains route parameters?

I'm working on an ASP.NET MVC4 web app, and I have a controller method for handling a GET request with an id in the URL, like so ...
[PortalAuthorization]
public ActionResult View(int id)
{
// get the individual ftp log
PortalFTPLog log = PortalFTPLogs.Get(id);
if (log == null)
{
TempData["Error"] = "The provided ftp log id does not exist.";
return RedirectToAction("Index");
}
// get the available matters to tie uploads to
ViewBag.matters = PortalMatters.Get();
return View(log);
}
In my view for this controller method, I have a form so that they can update it, that I want to POST back to the same URL. A URL like foo.com\items\1. Thats what the function above handles.
How do I make a function that handles a POST request for a function that requires a parameter, though? IN previous POST handlers I create a FormsCollection param, but when I add it to the param list for this function, the id param is null.
[HttpPost]
[PortalAuthorization]
public ActionResult View(FormCollection collection, int id)
{
PortalFTPLog log = PortalFTPLogs.Get(id);
if (log == null)
{
TempData["Error"] = "The provided ftp log id does not exist.";
return RedirectToAction("Index");
}
// update the matter id and save to database
log.Matter = Convert.ToInt32(collection.Get("matter"));
log.Save();
TempData["Notice"] = "The FTP log meta data has been updated.";
return RedirectToAction("View", new { id = id });
}
You need to provide RouteValues in Html.BeginForm on your View:
#using (Html.BeginForm(new {id = someIntIdValue}))
{
// Your form code
}

open a new window of view when call controller from Jquery Ajax post call

I'm using ASP.Net MVC2. I'm trying to open a new window of view when call controller from Jquery Ajax post call.
here is my code..
in ascx page..
$('#DeleteButton').click(function () {
var isLineChecked = $(':checkbox:checked', '#providerSearchResultsTable').length;
if (isLineChecked == 0) {
alert("Please select at least one row ");
return false;
}
else {
var params = {
Id: gaiSelected.join(',')
};
alert(params);
$.ajax({
type: "Post",
url: "SelectProviderAndContact",
data: params,
success: function (html) {
**//$('#SelectProviderAndContact').html(html);**
}
});
}
});
here is my controller Action method
[SessionFilter]
public ActionResult SelectProviderAndContact(string Id)
{
try
{
List<ProviderBaseInfo> providerList = null;
string[] internalProviderIDs = Id.Split(",".ToCharArray());
//string[] billingProviderNames = billingProvider.Split(",".ToCharArray());
IStateBag stateBag = _commonModel.GetStateBag();
//stateBag.SetValue("InternalProviderId", Id);
List<Guid> internalProviderIds = new List<Guid>();
foreach (var a in internalProviderIDs)
{
internalProviderIds.Add(new Guid(a));
}
List<Contacts> providerContactList = _providerModel.GetProviderContactlist(internalProviderIds);
if (providerContactList.Count <= 0)
{
//IStateBag stateBag = GetStateBag();
List<ProviderBaseInfo> providers = (List<ProviderBaseInfo>)stateBag.GetValue(ProviderListCache);
if (providers == null)
{
providerList = _providerModel.GetProviderCompleteList(null, null, null, null, Id).ToList();
}
else
{
providerList = providers.Where(x => internalProviderIds.Contains(x.InternalProviderId)).ToList();
}
providerContactList = _providerModel.GetContactlistbyInsertingProviders(providerList);
}
ViewData["ProviderNotFound"] = false;
// ViewData["ProviderName"] = new SelectList(billingProvider.Select(x => new { value = x, text = x }), "value", "text");
var Provider = new[] {
new { ProviderId = "A", Providername = "A" }
//new DataContracts.RegionKeyValues { RegionId = "B", RegionValue = "B" },
//new DataContracts.RegionKeyValues { RegionId = "D", RegionValue = "D" }
};
ViewData["ProviderName"] = new SelectList(Provider, "ProviderId", "Providername");
**return View("SelectProviderAndContact",providerContactList);**
}
catch (FaultException<MedicareFault> ex)
{
if (ex.Code.Name == typeof(ArgumentException).Name)
{
ViewData["ProviderNotFound"] = true;
ViewData["Error"] = ex.Reason;
return View((object)null);
}
else
{
ViewData["Error"] = Errors.Common.UnknownError;
return View((object)null);
}
}
catch
{
ViewData["Error"] = Errors.Common.UnknownError;
return View((object)null);
}
}
and I have created SelectProviderAndContact.aspx in view.
Please any one help me to open another window with SelectProviderAndContact.aspx
from ajax post call.
Your jquery will have to do almost all the work in opening a window. Using the window.open() method in your javascript you can make your controller send back a specific argument that causes it to open a new window with a certain URL (i.e. TheSmallPopupPageThatViewsResults.aspx?resultId=12345 or something).
Your controller would just decide whether or not to tell the view to open the new window and the view would then open it if it is told to.
With your specific implementation, you may have to create a model or something that stores results in the database so that the controller can save the result and the action and view that are for the popup page can then access that result. Another way of doing it would be to have the arguments that the popup page is called with determine what is viewed on the page. This would eliminate the need for another model, but your urls could get really long really fast if you have a lot of data and I believe that there is generally a limit to how long those urls can be.
I would recommend using JSON or XML to return the data to the javascript so that you can extend the returned object as much as needed. The way I have done it in the past is made several XML tags like <alert>, <refresh>, <redirect>, <somePageSpecificAction>, etc that I have jquery parse using $(theEnclosingTag).each( function () { //...parse here }).
I use mainly MVC3 so I don't know if this is supported in MVC2, but changing ActionResult to JsonResult for the return type and using return this.Json(new { put = "data here" }); for your return statements makes it really easy to use json.
Also, It may be beneficial to use a different action method to process ajax requests. You would then have one action that displays the page, another action to process ajax requests from that page (it could be decorated with [HttpPost] or something), and another method for your popup page view. That would also keep your code short and easier to read. Having long controller methods can get really confusing later down the line when you try to find the location of a specific bug.
EDIT: A specific example: Assuming MVC3 (since that is what I use...I think you can find other ways of doing this...you could use an xml serializer and just output xml) you have your page (Action #1) that displays with all your buttons and stuff (this is where you javascript containing the $("#DeleteButton") and such goes as well). Your javascript makes its AJAX call to another action (SelectContactAJAX or something...this is action #2) with a few arguments which has a return type of JsonResult. Your javascript gets the response back from that ajax-specific action and the response tells it "open a window with the URL /SelectContactForm?choiceId=12345" (or something). The choiceId is a reference that would be used in the background for the SelectContactForm action (yet another separate action...action #3) to know what to display. Your ajax would then call window.open("/SelectContactForm?choiceId=12345") and when the window opens, it calls action #3 which looks up the reference for what it should be displaying and then shows that to the user.
As for getting feedback on what the user entered in the new window and having the original page react, there are various ways in javascript to listen for window closings and such, but I haven't ever had to use this in one of my applications and it is a bit out of the scope of this question.
use colorbox jquery plugin
http://www.jacklmoore.com/colorbox
write code in .aspx page to call .ascx page
parent.$.fn.colorbox({ href: '/IGTR/SaveIGTRPreference/' + id + '?t=' + Math.random(), height: "400", width: "800", overlayClose: false, escKey: false
});
Here SaveIGTRPreference is .ascx page

ASP.NET MVC Remove query string in action method

I have an action method that looks like this:
public ActionResult Index(string message)
{
if (message != null)
{
ViewBag.Message = message;
}
return View();
}
What happens is that the url of a request to this will look like:
www.mysite.com/controller/?message=Hello%20world
But I want it to look just
www.mysite.com/controller/
Is there a way to remove the query string inside the actionmethod?
No, unless you use a POST method, the information has to get passed somehow. An alternative may be to use an in-between class.
// this would work if you went to controller/SetMessage?message=hello%20world
public ActionResult SetMessage(string message)
{
ViewBag.Message = message ?? "";
return RedirectToAction("Index");
}
public ActionResult Index()
{
ViewBag.Message = TempData["message"] != null ? TempData["message"] : "";
return View();
}
Or. if you simply used a POST
//your view:
#using(Html.BeginForm())
{
#Html.TextBox("message")
<input type="submit" value="submit" />
}
[HttpGet]
public ActionResult Index()
{ return View(); }
[HttpPost]
public ActionResult Index(FormCollection form)
{
ViewBag.Message = form["message"];
return View();
}
You can remove the query string by adding some JavaScript in the razor view.
#section scripts{
<script>
if (location.href.includes('?')) {
history.pushState({}, null, location.href.split('?')[0]);
}
</script>
}
If you navigate to page
www.mysite.com/controller/?message=Hello%20world
Then it'll show
www.mysite.com/controller/
in the browser.
Most modern browsers support this (browser support).
Look into routes. They define how a url with parameters will be written.
If you create a new MVC application, and look at the Global.asax.cs file under `RegisterRoutes(). you should see one entry.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "home", action = "index", id = UrlParameter.Optional } // Parameter defaults
);
Look at each part:
"Default" is the name. This just has to be unique for each route you create.
"{controller}/{action}/{id}" is the pattern you want to use. example.org/home/index?id=2 will be written example.org/home/index/2 instead
new { controller = "home", action = "index", id = UrlParameter.Optional } is defining the defaults if nothing is specified.
So, that route make it so if you go to example.org it will assume you mean example.org/home/index{id is optional}.
Working from that, you can start to see how to create your own routes.
Now, addressing your question the short answer is yes you could make the URL look like that, but not really. You would have to define a route with a default message, and it would only look like that if someone didn't specify a message. You have to tell the controller what the message is. I'm sorry, but the best you can do is define a route that gives you
/message/Hello%20World and using string.replace make that look even nicer `'/message/hello_world'
I'm not sure you're really thinking that through. If you remove the query string... then you remove the query string.. ie, your page won't have the query string value to do whatever it needs to do.
There's a bunch of different hacks you could do.. all of them are not ideal. You could use javascript to strip out the query string. You could redirect to a querystring-less page after setting a session variable.. it's all pretty ugly.
Remember that what the user sees in the address bar is on the client. The client controls that. You can fiddle with it via javascript, but doing so is generally a bad idea. Since hiding things from the user can be considered malware-like behavior.
I recommend using a slug. Check out this post: SOF Slug post
In previous applications, I took this approach to remove querystrings from the URL.

Resources