Render error view when we encounter an exception - c#

How can I do this in another way ?
public ActionResult SomeAction(int id)
{
try
{
var model = GetMyModel(id);
return View(model);
}
catch(Exception e)
{
var notFoundViewModel = new NotFoundViewModel { Some Properties };
return View("~/Views/Shared/NotFound.cshtml", notFoundViewModel);
}
}
Exception will be thrown for url Controller/SomeAction/NotFoundId. I hate to have in project something like: ~/Views/Shared/NotFound.cshtml.

I realize this question is a few years old, but I figured I would add to the accepted answer. Following CodeCaster's recommendation of using the standard "Error.cshtml" as the file (view) to act as your generic error page, I recommend you let the MVC framework do the rest of the work for you.
If you place the Error.cshtml file in the Shared folder in your MVC project, you do not need to explicitly specify the path to the view. You can rewrite your code like the following:
public ActionResult SomeAction(int id)
{
try
{
var model = getMyModel(id);
return View(model);
}
catch(Exception e)
{
var NotFoundViewModel = new NotFoundViewModel { Some Properties };
return View("Error", NotFoundViewModel);
}
}
In fact, I've noticed that if you supply an explicit path and are running the Visual Studio IIS Express on your local machine, it sometimes isn't able to find the file and displays the generic 404 message :(

You can return HttpNotFoundResult object as:
catch(Exception e)
{
return new HttpNotFoundResult();
}
or
catch(Exception e)
{
return HttpNotFound("ooops, there is no page like this :/");
}

Make it a "~/Views/Shared/Error.cshtml" that displays a generic error model with a title and a message?

Related

How to get user input from a textarea using C#

I'm trying to get the value of what the user has inputted in my textarea on my page and store that value as a string in a variable.
I have spent over an hour doing research on all different ways of getting the value from a textarea in C# and tried many combinations of example code and tried to adapt it to mine but neither of them work. Either the library doesn't exist anymore or something is wrong with example code and I don't want to fix something that is 8+ years old.
Is there any new ways in 2022 to get the value in my razor page textarea and store it in a string so I can re-use it for my needs?
I have seen the post on stack overflow that has been posted over 8+ years and it doesn't work or I'm implementing it wrong.
var mystr = document.getElementById(id).value;
you can put that in a javascript function then gets called on onlcick (like a submit button) and or on the textarea as OnTextChanged.
You have to provide the textarea's Id or use the Html helper method to get it. Here is a working example:
#using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using System;
public class HomeController : Controller
{
IConfiguration Configuration { get; }
public HomeController(IConfiguration configuration) => Configuration = configuration;
public IActionResult Index() => View();
[HttpPost]
public IActionResult Index(string path, string text) // Here you can specify the path of the html file and a text for it in this case will be used to grab the value of an input text area named 'Text'. But it works as well if you want to grab an input from a button and save it as another one in a new html file or somewhere else if you want to do something like that
{
try { var files = Directory.GetFiles(path); } catch (DirectoryNotFoundException) { return View("Error"); } catch (UnauthorizedAccessException) { return View("Error"); } catch (ArgumentNullException) { return View("Error"); } catch (ArgumentException) { return View("Error"); } catch (PathTooLongException) { return View("Error"); } catch (NotSupportedException) { return View("Error"); } catch (SecurityException) { return View("Error"); }
// Here you can get the value of your textarea and save it for further use
var input = Request.Form["Text"]; // This is an example
foreach (var file in files) { // Here you can loop through all the files, edit them or delete them
if (file.Contains(".cshtml")) { // You can just look for a specific file extension here if you want or loop through all the files in your directory, edit or delete any file
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(File.ReadAllText(file));
var formElement = htmlDocument.GetElementbyId("example-form").OuterHtml;
formElement = Regex.Replace(formElement, #"<input name=""Text"" type=""text"" value=""\s*?.*?"" />", "<input name=\"Text\" type=\"text\" value=\"" + input + "\" />");
var streamWriter = new StreamWriter(file); // Replace the content of the file with a string created on the previous line
streamWriter.WriteLineAsync(formElement);
}
}
return View("Index"); // Return your view to be called after saving or editing a file or not depending on what you are trying to do.
}
}
}

How to return the main view in another action within same controller?

So I'm struggling to tackle the following problem:
I have a main view called ApiBroker, in this view there are several methods to do something with the input from this view.
For example:
[HttpPost]
public ActionResult AddApi(ApiRedirect model)
{
var data = model;
try
{
List<ApiRedirect> list = dbProducts.ApiRedirects.ToList();
int companyID = dbProducts.Companies.Where(x => x.CompanyName == model.Company.CompanyName).FirstOrDefault().CompanyID;
int mappingID = dbProducts.MappingNames.Where(x => x.Name == model.MappingName.Name).FirstOrDefault().MappingID;
ApiRedirect api = new ApiRedirect();
api.ApiName = model.ApiName;
api.CompanyID = companyID;
api.ApiURL2 = model.ApiURL2;
api.MappingID = mappingID;
api.ResponseType = model.ResponseType;
dbProducts.ApiRedirects.Add(api);
dbProducts.SaveChanges();
return View();
}
catch (Exception ex){
throw ex;
}
}
This view should return the main View(Index) but instead of doing that its trying to return the View "AddApi" which does not exist. Error:
With the code above, the data gets inserted into my database but its returning me a 500 error.
What I've tried:
I've tried returning my View hard coded like this: return View("~/Views/ApiBroker/Index.cshtml"); but this gives me an error in my WebGrid.
I've also tried using "Return View("Index")", however this is me the following error in my WebGrid:
I've also tried "return View("Index",YourModel);", this is giving me the following error:
Hope someone can help!
You can return a particular View if they belong to the same Controller like this:
return View("Index");
If the View belongs to a different Controller, then you would simply have to specify the name of the View and its folder name and call it like this:
return View("../ControllerName/Index");
return RedirectToAction("YourAction");
or
return RedirectToRoute("YourRouteName");

MVC Backload File Upload failing in production

I've got a .NET 4.5 MVC 5 web application that utilizes Backload 2.0 to help with uploading an Excel file. The controller method works great in my development environment. However, when I moved to my production server, the same method is now failing.
It's failing because handler.Services.POST is null. All of the other properties off handler.Services are null as well, e.g. GET, etc.
What might cause this to happen? Is it an IIS setting? Web.config? What else can I check??
Most of this code was copied from an example that ships with Backload.
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post | HttpVerbs.Put | HttpVerbs.Delete | HttpVerbs.Options)]
public async Task<ActionResult> FileHandler()
{
try
{
// Create and initialize the handler
var handler = Backload.FileHandler.Create();
handler.Init(HttpContext.Request);
// Call the appropriate request handlers
if (handler.Context.HttpMethod == "POST")
{
// Get the posted file with meta data from the request
handler.FileStatus = await handler.Services.POST.GetPostedFiles();
if (handler.FileStatus != null)
{
var file = handler.FileStatus.Files[0];
DateTime spreadsheetDate;
using (var memoryStream = new MemoryStream((int)file.FileSize))
{
await file.FileStream.CopyToAsync(memoryStream);
//TODO: do some stuff...
}
}
// Create client plugin specific result and return an ActionResult
IBackloadResult result = handler.Services.Core.CreatePluginResult();
return ResultCreator.Create((IFileStatusResult)result);
}
// other http methods may also be handled
return new EmptyResult();
}
catch (Exception ex)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
}
Direct api calls (Services namespace) is a Pro feature and only works with the Pro Edition.
In your case I think you can switch to events with the same result. For example you can use the StoreFileRequestStarted event. Don't forget to enable events in the Web.Backload.config like described here:
https://github.com/blackcity/backload/wiki/Example-12
The demo package also includes an events example:
https://github.com/blackcity/Backload/releases/download/v2.1.0.0/Backload.Standard.2.1.Full.zip

Adding Image MediaType programatically Umbraco 7.1

Im a bit new to Umbraco, and i have to say i like it a lot.
But now i'm stuck on something simple i think. I Created a protected page that is only visible to members on my website. Where the member is able to upload multiple files at once. This is al working like a charm. First i created the upload form for multiple images then i created the SurfaceController to handle the submit. Also working like a charm.
My ActionResult on my SurfaceController receives an IEnumerable<HttpPostedFileBase> called files which is good. I see all my images that i'm posting with my form. But here comes the problem.
While looping over my files I try to create a Media (Image type) using the MediaService.CreateMedia giving my filename and parentid and the mediaType (Image).
But when i try to set the umbracoFile value on my just created media item i will get the following exception:
An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Umbraco.Core.dll
Additional information: The best overloaded method match for
'Umbraco.Core.Models.ContentBase.SetPropertyValue(string, string)'
has some invalid arguments
I hope someone can tell my what i'm doing wrong. Below is my code i'm using
[HttpPost]
public ActionResult UploadFiles(IEnumerable<HttpPostedFileBase> files)
{
bool success = false;
//Get logged in member and look for the mediafolderID
var member = Services.MemberService.GetByUsername(HttpContext.User.Identity.Name);
var mediaFolderID = member.GetValue<int>("mediaFolderID");
//Get mediafolder
var mediaFolder = Services.MediaService.GetById(mediaFolderID);
try
{
// Create a media item from each file uploaded
foreach (var file in files)
{
var fileName = file.FileName; // Assumes no path information, just the file name
var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower();
if (!UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Contains(ext))
{
var mediaType = global::Umbraco.Core.Constants.Conventions.MediaTypes.File;
if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.Contains(ext))
{
mediaType = global::Umbraco.Core.Constants.Conventions.MediaTypes.Image;
}
var f = Services.MediaService.CreateMedia(fileName, mediaFolderID, mediaType);
// Assumes the file.InputStream is a Stream - you may have to do some extra work here...
f.SetValue(global::Umbraco.Core.Constants.Conventions.Media.File,(Stream)file.InputStream); // Real magic happens here.
Services.MediaService.Save(f);
}
}
success = true;
}
catch (Exception ex)
{
// On error show message
ViewData["exceptionMessage"] = ex.Message;
success = false;
}
// On success redirect to current page and show successmessage
ViewData["success"] = success;
if (success)
{
return RedirectToCurrentUmbracoPage();
}
return CurrentUmbracoPage();
}
Instead of f.SetValue(global::Umbraco.Core.Constants.Conventions.Media.File, (Stream)file.InputStream); you should just use the HttpPostedFileBase: f.SetValue(global::Umbraco.Core.Constants.Conventions.Media.File, file);
Some other notes:
Check that the file has a length and is not null: file != null && file.ContentLength > 0
You're not using your mediaFolder variable anywhere, can be removed.
Not sure why you'd need global::Umbraco.Core, consider adding using Umbraco.Core; and use Constants.Conventions.MediaTypes.Image etc.
Check that you really need to rely on DisallowedUploadFiles - I'm pretty sure that's checked during CreateMedia

pass model from one action to another action in same controller

I am trying to pass my model List< Models.Statement > statementList from one action to another but i am receiving null value in the 2nd controller. Please suggest what is wrong here. Even tried with:
return RedirectToAction("WriteInTemplate", new { statementList = statementList });
Please help.
public ActionResult SendPdfStatement(string InvoiceNumber)
{
try
{
InvoiceNumber = InvoiceNumber.Trim();
ObjectParameter[] parameters = new ObjectParameter[1];
parameters[0] = new ObjectParameter("InvoiceNumber", InvoiceNumber);
List<Models.Statement> statementList = new List<Models.Statement>();
statementList = _db.ExecuteFunction<Models.Statement>("uspInvoiceStatement", parameters).ToList<Models.Statement>();
//WriteInTemplate(statementList);
return RedirectToAction("WriteInTemplate", statementList );
}
catch (Exception e)
{
InvoiceSearchTool.Models.udtExceptionTable exception = new udtExceptionTable();
exception.MethodName = "SendPdfStatement";
exception.Exception = e.ToString();
exception.Date = DateTime.Now;
DYNAMICS_EXTEntities db = new DYNAMICS_EXTEntities();
db.AddToudtExceptionTables(exception);
db.SaveChanges();
return View("Error");
}
}
public ActionResult WriteInTemplate(List<Models.Statement> statementList)
{
try
{
string invoiceNumber = statementList.FirstOrDefault().Invoice.ToString().Trim();
...................snip..........
return RedirectToAction("CreateMessageWithAttachment", "email", invoiceNumber);
}
catch (Exception e)
{
InvoiceSearchTool.Models.udtExceptionTable exception = new udtExceptionTable();
exception.MethodName = "WriteInTemplate";
exception.Exception = e.ToString();
exception.Date = DateTime.Now;
DYNAMICS_EXTEntities db = new DYNAMICS_EXTEntities();
db.AddToudtExceptionTables(exception);
db.SaveChanges();
return View("Error");
}
}
Please take a look here to pass your Model
you are not passing "statementList" , instead you are passing new { statementList= statementList} just pass the model and you should be fine .
return RedirectToAction("WriteInTemplate", statementList);
Answer by sino
RedirectToAction() writes a redirect command to the browser, making it start a brand new request to WriteInTemplate(). Your model object is therefore lost.
Is WriteInTemplate() an independent action which will sometimes be responsible for an entire request from a user or a partial request from a view? If not, you should just call it as a regular method instead of using RedirectToAction().
This is because you had spefified wrong route parameters.
while thinking about this.. did you check that the data are not null?
you are using
return RedirectToAction("WriteInTemplate", statementList );
instead you should use
return RedirectToAction("WriteInTemplate","controllerName", new{"statementList"=stetementList});
see reference here
The way you call the RedirectToAction() method may not be your issue.
For me, the solutions presented above did not work because the RedirectToAction() method builds a RouteValueDictionary by using the .ToString() value of each property in the model. This will only work if all the properties in the model are simple properties and it fails if any properties are complex objects, lists, collections, etc.
because this method does not use recursion.
If for example, a model called MymodelOrganization contained a property List Employees, then that property would result in a query string value of
....&Employees=System.Collections.Generic.List'1[System.String]
and binding would fail, and you would end up (as was my case) with ... null
I had this problem, so I created a copy of my model containing only the elements of the form, stripping my Lists and passed that inside RedirectToAction().
Once on the other action method, I was able to re-assemble my Lists and added them to my Model before calling the last return. Good luck. Here is the idea in my code:
[HttpPost]
public ActionResult ItemSubmissionForm(CombinedModelContent membervalues)
{ ...
ItemSubmissionsDBFields aFieldsList = membervalues.FieldsList; //Stripping other objects
return RedirectToAction("ItemSubmissionConfirm", aFieldsList);
}
[HttpGet]
public ActionResult ItemSubmissionConfirm(ItemSubmissionsDBFields aFieldsList)
{ ...
List<SomeArea> SomeAreaitems = new List<SomeArea>();
SomeAreaitems.Add ...
CombinedModelContent copymembervalues = new CombinedModelContent();
copymembervalues.SomeCodeLists = SomeAreaitems;
copymembervalues.FieldsList = aFieldsList;
return View("SomeConfirmPage", copymembervalues);

Categories

Resources