MVC4 - How to call controller method from razor view - c#

i am new with MVC, can someone please help me and explain how to call controller method from a view.
I have HomeController and inside it I have method ShowFileContent().
[HttpPost]
public ActionResult ShowFileContent()
{
string filepath = Server.MapPath("\\Files\\Columns.txt");
try
{
var lines = System.IO.File.ReadAllLines(filepath);
foreach (var line in lines)
{
ViewBag.FileContent += line + "\n";
}
}
catch (Exception exc)
{
ViewBag.FileContent = "File not found";
}
return View();
}
Inside view I've tried to call this method with code bellow but it does not work.
#using (Html.BeginForm("ShowFileContent", "Home"))
{
<input type="submit" value="Show File" style='width:300px'/>
}
<h2>#Html.Raw(ViewBag.FileContent.Replace("\n", "</br>"))</h2>
I get error: The view 'ShowFileContent' or its master was not found or no view engine supports the searched locations.
What i am doing wrong and whats the best way to call methods from razor view ?

You can use inbuilt Action method to call action from View.
#Html.Action("actionName", "ControllerName")

It sounds to me like its breaking on your
return View();
If you dont tell it where to go it thinks the view is called the same as your action.
so instead try
return View("Name of your view");

Related

How to create server method, that populates collection and returns partial view, in ASP.NET MVC?

I am trying to call IEnumerable method in my _Layout.cshtml file. At the final I was adviced to "use html.action - to call server method that populates collection and returns partial view".
Currently I have created partial file _Dodatki.cshtml, that contains call of IEnumerable method (Aktualnosci.cs is model file):
#model IEnumerable<DluzynaSzkola.Models.Aktualnosci>
In my _Layout.cshtml I called method from my constructor with:
#Html.Action("_Dodatki", "AktualnosciController ", new {area="" })
And at the final I want to create method in my AktualnosciConstructor.cs file. Currenly I have method:
[ChildActionOnly]
[ActionName("_Dodatki")]
public ActionResult Dodatki()
{
IList<Aktualnosci> lista = new IList<Aktualnosci>();
return PartialView("_Dodatki", lista);
}
Unfortunately, when using syntax as above, it gives me message in compiler:
"cannot create an instance of the abstract class or interface
'IList'".
When replacing 'IList' with 'List', it gives me exception:
"System.Web.HttpException: The controller for path '/' was not found
or does not implement IController."
I have no idea how in other way I can populate collection in the method.
edit: As per request, below AktualnosciController.cs definition, with no other methods:
namespace DluzynaSzkola.Controllers
{
public class AktualnosciController : Controller
{
//here are other methods
[ChildActionOnly]
[ActionName("_Dodatki")]
public ActionResult Dodatki()
{
IList<Aktualnosci> lista = new IList<Aktualnosci>();
return PartialView("_Dodatki", lista);
}
}
}
as noticed by GTown-Coder your controller name seems wrong. Updated my answer accordingly.
I think that your problem might be the same as answered by this SO post.
try specifying the Area name and, if this controller is not in an area simply add an empty area name.
#Html.Action("_Dodatki", "AktualnosciController ", new {area="" })
Even if this does not solve your problem it is good practice because if this view is latter used within an area it will try to find the controller in the area and not in the root space.
Allright, I have implemented changes to my project, that works fine.
My in _Layout.cshtml call is changed a bit. AktualnosciController supposed to be called just Aktualnosci !!!
<div class="kontenerDodatkiLayout hidden-xs hidden-sm">
<div class="archiwum">Archiwum</div>
#Html.Action("_Dodatki", "Aktualnosci", new { area = "" })
</div>
My partial view _Dodatki.cshtml model call is changed a bit:
#model IEnumerable<DateTime>
<div class="wpisDodatki">
#foreach (var item in Model)
{
<div> #Html.DisplayFor(modelItem => item)</div>
}
<p>test<br />test<br />test</p>
</div>
And method in my controller AktualnosciController.cs looks like that:
//[ChildActionOnly]
[ActionName("_Dodatki")]
public ActionResult Dodatki()
{
using (var context = new DluzynaContext())
{
var lista = context.Indeks.Select(it => it.Dzien).ToList();
return PartialView("_Dodatki", lista);
}
}
in here lista is passed to my partial view _Dodatki, and it is populated with context property Indeks and model property Dzien.
Thanks guys for your help #Wndrr , #GTown-Coder.

How to show Message Box in MVC ASP.NET without return View()

i'm new here in stackoverflow and also new to asp.net i would like to ask how to show message box in mvc asp.net. This is my code, but it will return NullReferenceException. Thanks for your help.`
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult myfunction(MyViewModels myModel)
{
System.Web.UI.ScriptManager script_manager = new System.Web.UI.ScriptManager();
if (ModelState.IsValid) {
createRequest(myModel);
script_manager.Page.ClientScript.RegisterStartupScript(this.GetType(), "showMyMessage", "ShowMessage('Requested Successfully.');", true);
return RedirectToAction("GeneratePDF", "Forms", myModel);
}
else
{
script_manager.Page.ClientScript.RegisterStartupScript(this.GetType(), "showMyMessage", "ShowMessage('Requested failed.');", true);
return RedirectToAction("Index");
}
}`
There are different ways to do the same thing, I have added three different ways and you can use, whatever required for you in different times.
Way 1: [Recommended for your requirement without return view()]
public ContentResult HR_COE()
{
return Content("<script language='javascript' type='text/javascript'>alert ('Requested Successfully ');</script>");
}
Official definition for content result class:
Represents a user-defined content type that is the result of an action method.
Source: https://msdn.microsoft.com/en-us/library/system.web.mvc.contentresult(v=vs.118).aspx
Other useful examples if required:
http://www.c-sharpcorner.com/UploadFile/db2972/content-result-in-controller-sample-in-mvc-day-9/
https://www.aspsnippets.com/Articles/ASPNet-MVC-ContentResult-Example-Return-String-Content-from-Controller-to-View-in-ASPNet-MVC.aspx
Other ways:
Way 2:
Controller Code:
public ActionResult HR_COE()
{
TempData["testmsg"] = "<script>alert('Requested Successfully ');</script>";
return View();
}
View Code:
#{
ViewBag.Title = "HR_COE";
}
<h2>HR_COE</h2>
#if (TempData["testmsg"] != null)
{
#Html.Raw(TempData["testmsg"])
}
Way 3:
Controller code:
public ActionResult HR_COE()
{
TempData["testmsg"] = " Requested Successfully ";
return View();
}
View code:
#{
ViewBag.Title = "HR_COE_Without using raw";
}
<h2>HR_COE Without using raw</h2>
#if( TempData["testmsg"] != null)
{
<script type="text/javascript">
alert("#TempData["testmsg"]");
</script>
}
I have used all the three ways personally and I got the output as expected. So Hope it will be surely helpful for you.
Kindly let me know your thoughts or feedbacks
Thanks
Karthik

Tag Helper forms: asp-for not working as expected

Thanks for the help so far. I've worked to make sure everything else works so I can focus on this problem. I'm still convinced it'll be an easy fix once we've cracked it. I have the following code, sorry I changed it so much, I had to start again after I made a real mess of the last one without taking a backup.
public IActionResult Index()
{
if(IndexModel.GlobalTasks == null)
{
IndexModel initModel = new IndexModel();
initModel.AllTasks = InitList();
initModel.EmptyTask = new ToDoTask();
IndexModel.GlobalTasks = initModel.AllTasks;
}
IndexModel model = new IndexModel();
model.AllTasks = IndexModel.GlobalTasks;
model.EmptyTask = new ToDoTask("");
return View(model);
}
//Create Task
public IActionResult Create(ToDoTask indexModel)
{
IndexModel.GlobalTasks.Add(indexModel);
return RedirectToAction("Index");
}
And:
#model DE.Models.IndexModel
<h2>To Do List</h2>
<form asp-action="Create">
<input asp-for="EmptyTask" value="#Model.EmptyTask" />
<input asp-for="EmptyTask.TaskDetails" placeholder="New Task" />
<button type="submit">Add Task</button>
</form>
The good news is this creates a new ToDoTask. So the Controller code must be pretty close to spot on. The problem is the View is passing null details to the controller, so I'm getting an empty Task, which isn't what I want.
Any ideas?
Using Tag Helper forms:
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<section >
<input type="text" asp placeholder="Title" asp-for="MyWork.Title"/>
</section >
Your controller action expects a ToDoTask object while your view uses a TaskViewModel object.
Try using the same type in both of them.
In your Create() method you need to instantiate the ToDoTask object, I think. So try this:
[HttpPost]
public IActionResult Create(ToDoTask newTask)
{
newTask = new ToDoTask();
return RedirectToAction("Index");
}
You may also need to return the ToDoTask object.

Message Box when item saved

Hi people I am new to this website was having trouble with my controller in C# MVC3 and when I gave up on looking for answers since i spent like 2 weeks on it I decided to join here.
The problem is I want a very simple confirmation message when I create a item in my application. I tried a If statement but I can't get the context correct. Can you kind people please help me thank you. My code:
//
// POST: /News/Create
[HttpPost]
public ActionResult Create(BooksItem booksitem)
{
try
{
using (var db = new BooksForever2())
{
db.NewsItems.Add(booksitem);
db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
The create works fine I can add books and it saves but I want when it saves a message appears so it shows the user its has been saved. I have tried: Viewbag.Message("Saved")
But this does not work. Any help will be truly appreciated
Thank You
Just add this in you controller
TempData["Message"] = "Saved";
then in your view:
#if(TempData["Message"] != null)
{
<p>#TempData["Message"].ToString()</b> #* or whatever element you need to show*#
}
at your view level you can do anything with the message (maybe flash it with jQuery):
jquery: Flash messages
UPDATE: I replaced ViewBag with TempData because I noticed you are doing a redirect, in which case the ViewBag won't persist but TemData would
Where do you want that confirmation message displayed? On the same edit form you are already on, or back on the index/list page?
Right now at the end of your method, you are redirecting to the Index action/page:
return RedirectToAction("Index");
The result of that is that the Index page will be loaded, and it will be completely unaware of where it came from other that something was saved.
Your two options, as I see it, are:
1) Stay on the current page, and display the message. You can add that message to the ViewBag like as has already been mentioned:
ViewBag.Message = "Saved"`
And then display it like this:
#if(ViewBag.Message != null)
{
<p>#ViewBag.Message</p>
}
and then make sure you remove the RedirectToAction and just return the default View, otherwise will still bounce you to the Index page.
2) Or, you can redirect the user back to the Index page, passing the message to be displayed, and then have the Index page look for that message. So when you call RedirectToAction, include a query string parameter:
ViewBag.Message
return RedirectToAction("Index", new { Message="Saved" });
Which will redirect you to ".../yourControllerName/Index?Message=Saved". Then you can add this to your Index action method:
if(!string.IsNullOrEmpty(QueryString["Message"]))
{
ViewBag.Message = QueryString["Message"];
}
And include that same view code in your index view:
#if(ViewBag.Message != null)
{
<p>#ViewBag.Message</p>
}

How to call and return the output of another controller's action inside an action?

We are working on a 'plugin' architecture for our project where to extend the software's functionality, client can write their own controllers and include it with the project. (The plugins are to generate different outputs based on tables which the client will add into the schema).
The plugins are accessed through an action in a controller's action, say like /reports/get/?type=spending
So in this case, the action will have to location a controller inside the 'plugin' area and invoke the index action (eg. areas/plugin/spending/index). How do I invoke this action while inside the /reports/get/?type=spending action, and get its output?
Html.RenderAction Method is used for rendering other action's output in view. Inpired from that, same in controller would be
using System.Web.Mvc.Html;
public void Index()
{
StringBuilder resultContainer = new StringBuilder();
StringWriter sw = new StringWriter(resultContainer);
ViewContext viewContext = new ViewContext(ControllerContext, new WebFormView(ControllerContext, "fakePath"), ViewData, TempData, sw);
HtmlHelper helper = new HtmlHelper(viewContext, new ViewPage());
helper.RenderAction("create");
sw.Flush();
sw.Close();
resultContainer.ToString(); //"This is output from Create action"
}
public ActionResult Create()
{
return Content("This is output from Create action");
}
Actually, RenderAction can be passed all the routing data you want, not only action name
RedirectToAction is probably the best option - that way you can use the built in routing to find the right action - something like
return RedirectToAction("Index", "SpendingPlugin");
If you don't want a redirect you can find and call the controller method directly as Nathan suggested, but that tends to get unnecessarily complex and interfere with locating views.
NOTE: This solution may seem kind of complex but it does seem to be the only way to solve the problem as described by the questioner in both his question and more specifically the comment on his question which states, "It's about creating the controller that is being requested, and reading the output from the actionresult. " (emphasis mine)
Controllers and actions are just fancy names for classes and methods. Why not just instantiate the controller like you would any other class and then call the index action on the controller? The hardest part would be instantiating the controller since you're going for the 'plugin' architecture and all the information you have about the controller is it's name as a string. Nothing a little reflection wouldn't solve though:
// GET: /reports/get/?type=spending
public Controller Reports
{
public ActionResult Get(string typeName)
{
Type typeOfController;
object instanceOfController;
try
{
typeOfController = System.Reflection.Assembly.GetExecutingAssembly().GetType(name: typeName, throwOnError: true, ignoreCase: true)
instanceOfController = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(typeName: typeName, ignoreCase: true);
}
catch(Exception ex)
{
// Controller not found
return View("InvalidTypeName");
}
ActionResult result = null;
try
{
result = typeOfController.InvokeMember("Index", System.Reflection.BindingFlags.InvokeMethod, null, instanceOfController, null)as ActionResult;
}
catch(Exception ex)
{
// Perhaps there was no parametersless Index ActionMethod
// TODO: Handle exception
}
return result;
}
}

Categories