I'm a beginner at programming and I'm trying to build a mvc application that can search a directory and display all the ones found in a view.I have an error message pop up when I search. If someone would tell me what I'm doing wrong or point me in the right direction it would be greatly appreciated.
error message is this:
> The view 'C:\Users\carrick\Downloads' or its master was not found or
> no view engine supports the searched locations. The following
> locations were searched:
> ~/Views/DirectorySearch/C:\Users\carrick\Downloads.aspx
> ~/Views/DirectorySearch/C:\Users\carrick\Downloads.ascx
> ~/Views/Shared/C:\Users\carrick\Downloads.aspx
> ~/Views/Shared/C:\Users\carrick\Downloads.ascx
> ~/Views/DirectorySearch/C:\Users\carrick\Downloads.cshtml
> ~/Views/DirectorySearch/C:\Users\carrick\Downloads.vbhtml
> ~/Views/Shared/C:\Users\carrick\Downloads.cshtml
> ~/Views/Shared/C:\Users\carrick\Downloads.vbhtml
my controller looks like this
public class DirectorySearchController : Controller
{
//
// GET: /DirectorySearch/
public ActionResult Index()
{
return View();
}
public ActionResult GetDirFiles(string directorySearch)
{
//first check directorySearch is a valid path
//then get files
Directory.GetFiles(directorySearch);
ViewBag.message = directorySearch;
return View(ViewBag.message);
}
}
}
and my view
#{
;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>GetDirFiles</title>
</head>
<body>
<div>
<h2>Search Results</h2>
<ul>
<li>#Viewbag.message;</li>
</ul>
</div>
</body>
</html>
This line:
return View(ViewBag.message);
You are telling it to render the view with the name of the directory files, hence why you are getting that error messaging. ViewBag is already passed into your view so you don't need to pass it yourself.
You most likely just want to have the empty parameter call of
return View();
Which will by default return the view of with the name of the method in your controller.
Besides that you are not passing the files to the view, you are passing the path. You will need to do something like this. Note the case of ViewBag(not Viewbag)
Controller:
ViewBag.message = string.Join(",", Directory.GetFiles(directorySearch));
View:
<li>#ViewBag.message</li>
Or you can write a simple loop in your view
Controller:
ViewBag.message = Directory.GetFiles(directorySearch);
View:
#foreach(string file in ViewBag.message)
{
<li>#file</li>
}
In this line
return View(ViewBag.message);
Change it to
return View();
The first argument is the ViewName. ViewBag is passed to the view ambiently/implicitly, so you dont need to pass it on.
Related
I am learning C# using DotNetFiddle to code.
I have a web with a bunch of radio buttons and when I click them I want to update the view, for example: delete one button.
Also I need to do the delete logic in the backend and from the view I have to call a POST method to pass data.
So I'm trying to call the POST method with ajax and return RedirectToAction to display the new view, but somehow is not working.
You can check and test my current code here: dotnetfiddle
Controller
using System;
using System.Web.Mvc;
using System.Collections.Generic;
namespace HelloWorldMvcApp
{
public class HomeController : Controller
{
public SampleViewModel sampleViewModel = new SampleViewModel();
[HttpGet]
public ActionResult Index()
{
return View(sampleViewModel);
}
[HttpPost]
public ActionResult UpdateList(string id)
{
sampleViewModel.deleteElement();
return RedirectToAction("Index");
}
}
}
Model
using System;
using System.ComponentModel.DataAnnotations;
namespace HelloWorldMvcApp
{
public class SampleViewModel
{
public List<string> list = new List<string> { "a", "b", "c", "d", "e"} ;
}
}
View
#model HelloWorldMvcApp.SampleViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<!-- template from http://getbootstrap.com/getting-started -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- CSS Includes -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
</head>
<body>
<br/>
<div class="container">
<br></br>
<ul>
#foreach (var c in Model.arr)
{
<li>
<input type="radio" name="option" id="#c">#c
</li>
}
</ul>
</div>
<!-- JS includes -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript">
$('input[type=radio]').click(function() {
var elemId = $(this).attr("id");
$.ajax({
url: '#Url.RouteUrl(new{ action="UpdateList", controller="Home"})',
data: { id : elemId },
type: "POST"
});
});
</script>
</body>
</html>
UPDATE
I've edited your Fiddle into this: https://dotnetfiddle.net/zQq3aR
It does exactly what I describe below in the original answer, but uses the main view. Note that this is NOT what I would recommmend... we're rendering the entire view again, and then replacing the entire page contents with the new content, but I'm not too familiar with DotNetFiddle and don't know how to add more views (can you?).
C#:
[HttpPost]
public ActionResult PostToMe(string id)
{
// TODO: Do some stuff here, then return the updated view
return ButRenderMe(id);
}
[HttpPost]
public ActionResult ButRenderMe(string id)
{
// Remove some content from the model
sampleViewModel.arr = new [] { "a", "b", "c", "all of the above" };
return View(sampleViewModel);
}
JavaScript:
$.ajax({
url: '#Url.RouteUrl(new{ action="PostToMe", controller="Home"})',
data: { id : elemId },
type: "POST",
success: function(data) {
document.open();
document.write(data);
document.close();
}
});
The better way to do this in a normal MVC project would be to have a PartialView used for rendering the content you want to replace... in this case the list. In your "update" action you would update your data, and then re-render just that PartialView and return it. Then replace just that section with the new content.
With the code above, from my Fiddle, we may as well be making a normal page post instead of an AJAX call.
There are a lot of factors here, but hopefully this helps.
ORIGINAL ANSWER
So this is a bit confusing, given that your question doesn't match your code in either the DotNetFiddle or the question itself, but let's see if this helps.
I'm pretty sure that returning a RedirectToAction Result doesn't return the content from the other action your redirecting to. I think in this case, since it's an AJAX request, MVC knows that this isn't the proper usage, and returns a 200 OK status with the following example content. So with this Controller Action:
[HttpPost]
public ActionResult RedirectMe()
{
return RedirectToAction("UpdateList");
}
We get this Response:
<html><head><title>Object moved</title></head><body>
<h2>Object moved to here.</h2>
</body></html>
So again, I don't think that will work the way you want.
I think what you want is to Render the other action, and return that content back. And that should be as simple as calling that other action:
[HttpPost]
public ActionResult PostToMe(string id)
{
return ButRenderMe(id);
}
[HttpPost]
public ActionResult ButRenderMe(string id)
{
return Content("Test");
}
That returns the content "test". I think that you should be able to render a normal view in that other action if you want.
I looked at your DotNetFiddle as well...
In your DotNetFiddle your JavaScript is calling into UpdateList which doesn't seem to exist... not sure why it would even return a 200 OK... The Actions you have are Index and UpdateFlights. If you open the F12 Developer Tools in Chrome you should see that the POST returns no Content.
So I added a Controller Action called UpdateList:
[HttpPost]
public ActionResult UpdateList(string id)
{
sampleViewModel.deleteElement();
return Content("Test");
}
And I can see that "test" is returned as the Response content in the F12 Tools.
I needed two models in my view. So, as I was suggested, I created two partial views : Entete and ChampsFormulaireInvalidite, both with their models.
My Index View render these two views:
<head>
<title>Formulaire d'invalidité</title>
</head>
#{Html.RenderAction("Entete");}
#{Html.RenderAction("ChampsFormulaireInvalidite");}
In the Entete controller, I sometime catch an exception. When it does, I would like the entire page to be replaced by an error page. I tried this:
public PartialViewResult Entete()
{
try{
<some actions>
return PartialView ("Entete", model)
}
catch(Exception){
return PartialView ("Error")
}
}
Of course, since I return a PartialView, only the first half of my page displays the error view, while the other half displays a form (ChampsFormulaireInvalidite view). I would like to be redirected to a full error page when an exception is catched.
Any suggestion?
I tried to put a try catch in my index method with no success:
public ActionResult Index()
{
try{
return View("Index");
}
catch(Exception){return View("Error")}
}
Thanks to this video: https://www.youtube.com/watch?v=nNEjXCSnw6w
As suggested, I turned on the customErrors in my web.config:
<system.web>
...
<customErrors mode="On" />
</system.web>
And added an Error.cshtml view under Views/Shared:
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Erreur";
}
<h1 class="text-danger">Error</h1>
[EDITED] my previous question closed as duplicate, but I don't think so and I write why below. If I'm wrong, please leave a couple words of explanations if you decide to do it again. I'm newbie in dev, but I read a bunch of SO questions about topic which already been asked and still don't find answer
My goal is to create a form with input fields that can be added from View by clicking on button. I don't know how many fields a user want to add and also I need that form will be bound to List < MyModel > and when user send it'll return to action List < MyModel >.
I created sample project to show you my solution which doesn't work. Can you help me with it please?
MyModel
public class MyDogModel
{
public string Name { get; set; }
public string Breed { get; set; }
}
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
Session.Clear();
return View();
}
[HttpPost]
public ViewResult MyDogs (List<MyDogModel> myDogs)
{
return View(myDogs);
}
[HttpPost]
public PartialViewResult AddDog(List<MyDogModel> dogs)
{
int fieldsCount;
if (Session["FieldsCount"] == null)
{
Session["FieldsCount"] = 1;
fieldsCount = 1;
}
else
{
fieldsCount = (int)Session["FieldsCount"];
Session["FieldsCount"] = fieldsCount++;
}
return PartialView(dogs);
}
}
Index
#{
AjaxOptions options = new AjaxOptions
{
HttpMethod = "post",
UpdateTargetId = "MyDogsForm",
InsertionMode = InsertionMode.Replace
};
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="~/Scripts/jquery-1.8.0.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>
<body>
<div>
#Ajax.ActionLink("Add new dog", "AddDog", options)
<div if="MyDogsForm">
</div>
</div>
</body>
</html>
Here in AddDog View I'm getting null reference error in this string
#Html.TextBoxFor(d => d[i].Breed); Exception thrown: 'System.NullReferenceException' in System.Web.Mvc.dll
#model List<WebApplication2.Models.MyDogModel>
#using (#Html.BeginForm("MyDogs","Home"))
{
for (int i = 0; i < (int)Session["FieldsCount"]; i++)
{
#Html.TextBoxFor(d => d[i].Name);
#Html.TextBoxFor(d => d[i].Breed);
}
<button type="submit">Send</button>
}
What does it mean? I just want to fill my List with number of dogs which user'll want to add.
EDIT Thanks #stephen-muecke for suggested solution. Maybe I'm missing something. But actually I'm looking for solution, where form will created and fulfilled with some data at the server. In this answer POST a form array without successful new fields added by JQuery, I'll try it if server-side form changes via ajax not possible, but it'll be more convenient for me to avoid JQuery cause I need to bind not just TextBoxes, but DropDownLists and so on with information which generated on server from database.
I have one layout and one partial view which are in the Shared folder. Partial view presents top menu items which are not static. So I need to call an action method to get menu items from database. To do this, I created a controller and add an action method in it.
When I try to browse the page in web browser, this error occured:
The controller for path '/' was not found or does not implement IController.
Note:
I tried Html.RenderAction, Html.Partial methods too...
And I tried to create another view folder, and create a new partial view and new controller that named with "folder name + Controller" suffix.
Layout:
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
</head>
<body>
<div id="header">
#Html.Action("~/Views/Shared/_TopMenu.cshtml", "LayoutController", new {area =""}); //Here is the problem.
</div>
<div>
#RenderBody();
</div>
</body>
</html>
_TopMenu.cshtml:
#model IList<string>
#foreach (string item in Model)
{
<span>item</span>
}
LayoutController (in Controllers folder):
public class LayoutController : Controller
{
//
// GET: /Shared/
public ActionResult Index()
{
return View();
}
[ChildActionOnly]
[ActionName("_TopMenu")]
public ActionResult TopMenu()
{
IList<string> menuModel = GetFromDb();
return PartialView("_TopMenu", menuModel);
}
}
What happens if you put this in your view?
#{ Html.RenderAction("TopMenu", "Layout"); }
(And comment this out until everything works: //[ChildActionOnly])
Change this line,
#Html.Action("~/Views/Shared/_TopMenu.cshtml", "LayoutController", new {area =""});
to,
#Html.Action("_TopMenu", "Layout", new {area =""});
and check.
exist differents ways, for this case I like use html.action in layout, and in control I will create a string Menu, the string contains the html code I need, the controller end with return Content(menu);
for example
Layout:
<body>
<nav>
#Html.Action("_TopMenu", "Layout")
</nav>
the controller
public class LayoutController : Controller
{
public ActionResult _TopMenu()
{
IList<string> menuModel = GetFromDb();
string menu = "<ul>";
foreach(string x in menuModel)
{
menu +="<li><a href='"+x+"'>+x+"</a></li>";
}
menu+="</ul>";
return Content(menu);
}
}
I like that because I can use many options to create menus dinamics more complexes.
other way use ajax to recovered the data and use handlebars or other template for the code
You are using the wrong overload of the Action-Method. The 2nd parameter in the variation is not the controllername but the actionname.
You can check the correct Method overloads on this page
Also: If you specify Controllers in the Html.Action Method (which you can do for example with this variation of the Method), you dont need to write the suffix "Controller" even if thats your Classname. So Instead of using the string "LayoutController" you would write simply "Layout".
At this point the framework is convention-based.
This is how I did it:
Layout
#Html.Action("GetAdminMenu", "AdminMenu")
Admin Menu Controller
public PartialViewResult GetAdminMenu()
{
var model = new AdminMenuViewModel();
return PartialView(model);
}
GetAdminMenu.cshtml
#model ReportingPortal.Models.AdminMenuViewModel
<div class="form-group">
<label class="col-md-4 control-label" for="selectbasic">School Name</label>
<div class="col-md-8">
#Html.DropDownListFor(model => model.SelectedID, new SelectList(Model.DataList, "Value", "Text", Model.SelectedID), "", new { #class = "form-control", #required = "*" })
</div>
</div>
How do I use multiple actions on the same controller?
I'm using the default project that comes up when opening a new project in asp.net mvc.
I added one more Index action on the homecontroller to accept a value from a textbox...like this
string strTest;
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection frm)
{
strTest = frm["testbox"];
return RedirectToAction("Index");
}
Now,I need to display the entered value back to the user. How do I do this?
I tried this..
public ActionResult Index()
{
this.ViewData.Add("ReturnMessage", strValue);
return View();
}
Here's what I've put on my view..
<% using (Html.BeginForm())
{ %>
<p>
<%=Html.TextBox("testbox")%>
</p>
<p>
<input type="submit" value="Index" /></p>
<p>
<%= Html.ViewData["ReturnMessage"] %>
</p>
<% } %>
the compiler typically doesn't let me add another index with same constructor to display the entered message back to the user which is obvious in c# I know. But,then how do I get the message back out to the user.
Thanks
Well, a controller matches one route, based on the parameters sent. You can layer your routes from most specific to least specific, it checks in order. First one that hits wins.
The other answer is to either strongly type your model sent to your view, or store it in the ViewData:
ViewData["Message"] = "Welcome to ASP.NET MVC!";
Then access it in your View:
<%= Html.Encode(ViewData["Message"]) %>
Simple method
In your view
<% using (Html.BeginForm()) {%>
<%= Html.TextBox("myInput") %>
<%= ViewData["response"] %>
<%}%>
In your controller;
public ActionResult Index()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection collection)
{
ViewDate.Add("response", collection["myInput"]);
return View();
}
Josh, see the previous question you asked.
In there I had <%= Html.textbox("myInput", Model.myInput....
it's the Model.myInput that will put the value from your model into the text of yoru text box.
EDIT
Or if you don't want it in a text box then simply do;
EDIT 2
You can add as many items into your new form view model and it has, in this case, nothing to do with a database. see your previous question on where i declared the class.
the class can have as many properties as you like. So you can add a string myResponse {get;set;} to return a response back to your view so then you can use <%=Model.myResponse%>
Hope this helps.