I cant using Html.RenderAction in .cshtml - asp.net

FRONTEND
#{
<div>
#Html.RenderAction("UrunOzellikTipWidget", "Admin");
#Html.RenderAction("UrunOzellikDegerWidget", "Admin");
</div>
}
BACKEND
public ActionResult UrunOzellikEkle()
{
return View(Context.Baglanti.Urun.ToList());
}
public PartialViewResult UrunOzellikTipWidged(int? katID)
{
if (katID != null)
{
var data = Context.Baglanti.OzellikTip
.Where(x => x.KategoriID == katID)
.ToList();
return PartialView(data);
}
else
{
var data = Context.Baglanti.OzellikTip.ToList();
return PartialView(data);
}
}
public PartialViewResult UrunOzellikDegerWidget(int? tipID)
{
if (tipID != null)
{
var data = Context.Baglanti.OzellikDeger
.Where(x => x.OzellikTipID == tipID)
.ToList();
return PartialView(data);
}
else
{
var data = Context.Baglanti.OzellikDeger
.ToList();
return PartialView(data);
}
}
**ERROR CODE:Severity Code Description Project File Line Suppression State Error CS0029 Cannot implicitly convert type 'void' to 'object'
**

#Html.RenderAction renders the result and, instead of returns it as string, writes it directly to the response and returns Void. So you will have to use it inside a C# block, denoted as #{ }, and end it with a semicolon at the end, just like how you invoke/call a void function.
So your front-end needs to be changed to:
<div>
#{
Html.RenderAction("UrunOzellikTipWidget", "Admin");
Html.RenderAction("UrunOzellikDegerWidget", "Admin");
}
</div>
The other's answer (removing the redundant ampersands) won't work because those 2 RenderAction are wrapped inside a <div />. If you remove the ampersand, they're treated as just regular HTML. It will output as:

Revise your code in FRONTEND to the following (remove the redundant ampersands from both Html.RenderAction statements).
<div>
#{ Html.RenderAction("UrunOzellikTipWidget", "Admin"); }
#{ Html.RenderAction("UrunOzellikDegerWidget", "Admin") };
</div>

Related

Posting a search form via Ajax in ASP.NET MVC results in 500 (Internal Server Error)

So the way I have got this setup involves ClientController in the Controllers Folder. And in the Views Folder, I have SearchClient.cshtml and _SearchClients.cshtml. I am using Ajax and following the tutorial from this link : http://techfunda.com/howto/291/search-database-using-ajax to get my search to work.
Here is how the methods in my controller look like :-
public ActionResult SearchClient()
{
return View();
}
public PartialViewResult _SearchClients(string searchString = "")
{
var clients = repository.Get(c => c.isDeleted == false);
clients = clients.Where(s =>
(s.FirstName.Contains(searchString)) ||
(s.MiddleName.Contains(searchString)) ||
(s.LastName.Contains(searchString))
).ToList();
return PartialView(clients);
}
And finally , here is the partial view :-
#model IEnumerable<Entities.Client>
#foreach (var item in Model)
{
<tr>
<td>#item.FirstName</td>
<td>#item.MiddleName</td>
<td>#item.LastName</td>
<td>#item.Phone</td>
<td>#item.Email</td>
<td>#item.AgencyID</td>
<td>#item.StreetAddress</td>
<td>#item.City</td>
<td>#item.PostalCode</td>
<td>#item.Province</td>
</tr>
}
I figured that the MidddleName was null and had to remove it from the search. At the same time I had to check if the string was null or empty. Here is the Controller action.
public PartialViewResult _SearchClients(string searchString = "")
{
if (!String.IsNullOrEmpty(searchString))
{
var searchedClient = clients.Where(s =>
(s.FirstName.Contains(searchString)) ||
(s.LastName.Contains(searchString))
).ToList();
return PartialView(searchedClient);
}
return PartialView(clients);
}
Hope this helps someone.

Checkbox retains state after postback

how come my model retains the state? why is it like this?
Isn't it supposed to be refreshed since i am trying to send a brand new instance of the model?
Here is an example:
If i delete anything on the middle, after postback, the checkbox will still be checked
Here are my codes:
Here is my postback code:
[HttpPost]
public ActionResult Index(IEnumerable<Employee> emp)
{
EmployeeContext test = new EmployeeContext();
if (emp.Count(x => x.selected) == 0)
{
return View(test.Employees);
}
else
{
foreach (Employee del in emp)
{
if (del.selected)
{
Employee dummy = test.Employees.Single(x => x.id == del.id);
test.Employees.Remove(dummy);
test.SaveChanges();
}
}
return View(test.Employees);
}
}
What should i do to remove that state? i read something about ModelState.Remove so my idea is that use a loop to clear each of my checkboxes but i am not sure if that will be good when it comes to performance. What should i do?
Fixed by changing them to Redirect:
[HttpPost]
public ActionResult Index(IEnumerable<Employee> emp)
{
EmployeeContext test = new EmployeeContext();
if (emp.Count(x => x.selected) == 0)
{
return RedirectToAction("Index");
}
else
{
foreach (Employee del in emp)
{
if (del.selected)
{
Employee dummy = test.Employees.Single(x => x.id == del.id);
test.Employees.Remove(dummy);
test.SaveChanges();
}
}
return RedirectToAction("Index");
}
}
Full Credits to : Stephen Muecke for the PRG pattern.
if you didn't want model state keep it's value in the view, you don't need to pass the model into the view
just change this
return View(test.Employees);
into
return View();

jQuery and #Html.TextBoxfor()

I currently have the following code:
[HttpPost]
public ActionResult Index(IList<LocalPageModel> postPages,
IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
foreach (HttpPostedFileBase file in files)
{
if ((file != null) && (file.ContentLength > 0))
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/"),
fileName);
file.SaveAs(path);
}
}
}
else
{
ManagePagesModel mod = new ManagePagesModel
{
PostPages = postPages
};
return View("Index", mod);
}
return RedirectToAction("Index");
}
In my view, I have a JavaScript button which will add a div so that the user can post another page such as:
$("#add-page").click(function () {
$("#page").append('<div id="page"> #Html.TextBoxFor(u => u.PostPages[0].Title) </div>');
});
How do I make it so that when the user clicks on the JavaScript button, the new text will be appended to the page and u.PostPages[x] will be incremented?
If you want to do it all on the client (no AJAX), maybe don't use the MVC helpers at all, and do it manually instead - you know the HTML that will be rendered, so just do that:
var i = 0;
$("#add-page").click(function () {
$("#page").append('<input type="text" name="PostPages[' + (i++) + '].Title">');
});
Maybe clean the code up a bit so the quotes don't get too confusing, but you get the idea...
You didn't past your view, but I assume you have the following at the top:
#model = ManagePagesModel
If that's the case, you can then use the following #foreach to loop through the page models:
$("#add-page).click(function() {
#foreach(var pageModel in Model.PostPages){
$("#page").append('<div id="page"> #Html.TextBoxFor(u => pageModel.Title) </div>');
});
To increment u.PostPages[x] you may use following code:
<script>
var i = 0;
$("#add-page").click(function () {
i++
$("#page").append('<div id="page"> #Html.TextBoxFor(u => u.PostPages['+i+'].Title') </div>');
});
</script>
Here is small working example: jsfiddle

Making TPL Async calls from mvc controller on click of submit button

Basically I want to implement simple search functionality, whenever user enters some keyword in the text box on view and clicks submit button I want to make ASYNC calls to predefined website urls using TPL Async mechanism. When I do the same with console application it works like a charm but not with ASP.NET MVC3.
I couldn't find the reason
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
[HttpPost]
public ActionResult Index(string text)
{
string[] url = { "http://www.msnbc.com", "http://www.yahoo.com",
"http://www.nytimes.com", "http://www.washingtonpost.com",
"http://www.latimes.com", "http://www.newsday.com" };
Task<string[]> webTask = this.GetWordCounts(url, text);
string[] results = null;
try
{
results = webTask.Result;
}
catch (AggregateException e)
{
}
return View("Index", results);
}
//Taken from MSDN
Task<string[]> GetWordCounts(string[] urls, string name)
{
TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>();
WebClient[] webClients = new WebClient[urls.Length];
object m_lock = new object();
int count = 0;
List<string> results = new List<string>();
for (int i = 0; i < urls.Length; i++)
{
webClients[i] = new WebClient();
#region callback
// Specify the callback for the DownloadStringCompleted
// event that will be raised by this WebClient instance.
webClients[i].DownloadStringCompleted += (obj, args) =>
{
if (args.Cancelled == true)
{
tcs.TrySetCanceled();
return;
}
else if (args.Error != null)
{
// Pass through to the underlying Task
// any exceptions thrown by the WebClient
// during the asynchronous operation.
tcs.TrySetException(args.Error);
return;
}
else
{
// Split the string into an array of words,
// then count the number of elements that match
// the search term.
string[] words = null;
words = args.Result.Split(' ');
string NAME = name.ToUpper();
int nameCount = (from word in words.AsParallel()
where word.ToUpper().Contains(NAME)
select word)
.Count();
// Associate the results with the url, and add new string to the array that
// the underlying Task object will return in its Result property.
results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, name));
}
// If this is the last async operation to complete,
// then set the Result property on the underlying Task.
lock (m_lock)
{
count++;
if (count == urls.Length)
{
tcs.TrySetResult(results.ToArray());
}
}
};
#endregion
// Call DownloadStringAsync for each URL.
Uri address = null;
try
{
address = new Uri(urls[i]);
// Pass the address, and also use it for the userToken
// to identify the page when the delegate is invoked.
webClients[i].DownloadStringAsync(address, address);
}
catch (UriFormatException ex)
{
// Abandon the entire operation if one url is malformed.
// Other actions are possible here.
tcs.TrySetException(ex);
return tcs.Task;
}
}
// Return the underlying Task. The client code
// waits on the Result property, and handles exceptions
// in the try-catch block there.
return tcs.Task;
}
this is my view - for now I have hard coded keyword as microsoft
#using (Html.BeginForm("Index", "Home", new { text = "Microsoft" }))
{
<input type="submit" />
}
Update: It stays forever and inside the try block of Index Post method
I would recommend you using an AsyncController for this task to avoid jeopardizing ASP.NET worker threads which is one the worst thing that might happen to an ASP.NET application => running out of worker threads. It's like running out of fuel in the middle of the desert. You most certainly die.
So let's start by writing an extension method that will allow us converting the legacy WebClient event based pattern into the new task based pattern:
public static class TaskExtensions
{
public static Task<string> DownloadStringAsTask(this string url)
{
var tcs = new TaskCompletionSource<string>(url);
var client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
if (args.Error != null)
{
tcs.SetException(args.Error);
}
else
{
tcs.SetResult(args.Result);
}
};
client.DownloadStringAsync(new Uri(url));
return tcs.Task;
}
}
Armed with this extension method in hand we could now define a view model that will basically reflect the requirements of our view:
public class DownloadResultViewModel
{
public string Url { get; set; }
public int WordCount { get; set; }
public string Error { get; set; }
}
Then we move on to an asyncrhonous controller that will contain 2 actions: a standard synchronous Index action that will render the search form and an asynchronous Search action that will perform the actual work:
public class HomeController : AsyncController
{
public ActionResult Index()
{
return View();
}
[AsyncTimeout(600000)]
[HttpPost]
public void SearchAsync(string searchText)
{
AsyncManager.Parameters["searchText"] = searchText;
string[] urls =
{
"http://www.msnbc.com",
"http://www.yahoo.com",
"http://www.nytimes.com",
"http://www.washingtonpost.com",
"http://www.latimes.com",
"http://www.unexistentdomainthatwillcrash.com",
"http://www.newsday.com"
};
var tasks = urls.Select(url => url.DownloadStringAsTask());
AsyncManager.OutstandingOperations.Increment(urls.Length);
Task.Factory.ContinueWhenAll(tasks.ToArray(), allTasks =>
{
var results =
from task in allTasks
let error = task.IsFaulted ? task.Exception.Message : null
let result = !task.IsFaulted ? task.Result : string.Empty
select new DownloadResultViewModel
{
Url = (string)task.AsyncState,
Error = error,
WordCount = result.Split(' ')
.Where(x => string.Equals(x, searchText, StringComparison.OrdinalIgnoreCase))
.Count()
};
AsyncManager.Parameters["results"] = results;
AsyncManager.OutstandingOperations.Decrement(urls.Length);
});
}
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return View("index", results);
}
}
Now we define an ~/Views/Home/Index.cshtml view that will contain the search logic as well as the results:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
And of course the corresponding display template that will be rendered automatically for each element of our model (~/Views/Shared/DisplayTemplates/DownloadResultViewModel.cshtml):
#model DownloadResultViewModel
<tr>
<td>#Html.DisplayFor(x => x.Url)</td>
<td>
#if (Model.Error != null)
{
#Html.DisplayFor(x => x.Error)
}
else
{
#Html.DisplayFor(x => x.WordCount)
}
</td>
</tr>
Now, since the search operation could take quite a long time your users could quickly get bored without being able to use some of the other hundredths of functionalities that your webpage has to offer them.
In this case it is absolutely trivial to invoke the Search controller action using an AJAX request and showing a spinner to inform the users that their search is in progress but without freezing the webpage allowing them to do other things (without navigating away from the page obviously).
So let's do that, shall we?
We start by externalizing the results into a partial (~/Views/Home/_Results.cshtml) without touching at the display template:
#model IEnumerable<DownloadResultViewModel>
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
and we adapt our ~/Views/Home/Index.cshtml view to use this partial:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
<div id="results">
#Html.Partial("_Results")
</div>
and of course the SearchCompleted controller action that must now return only the partial result:
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return PartialView("_Results", results);
}
Now all that's left is to write a simple javascript that will AJAXify our search form. So this could happen into a separate js that will reference in our layout:
$(function () {
$('form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
success: function (results) {
$('#results').html(results);
}
});
return false;
});
});
Depending on whether you referenced this script in the <head> section or at the end of the body you might not need to wrap it in a document.ready. If the script is at the end you could remove the wrapping document.ready function from my example.
And the last part is to give some visual indication to the user that the site is actually performing a search. This could be done using a global ajax event handler that we might subscribe to:
$(function () {
$(document).ajaxStart(function () {
$('#results').html('searching ...');
});
});

JSON returned data formatting

I'm using code below to get JSON data:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
Json(getBranchList(AppSession.BranchID.Value));
}
private object getBranchList(int n)
{
var mybranchList = from p in getBranchs(n)
select new { p.Code, p.Name };
return mybranchList.ToArray();
}
Client side retain value :
[{"Code":000,"Name":"Milan"},
{"Code":001,"Name":"Istanbul"},
{"Code":002,"Name":"Baku"},]
But I want to get like this:
[{000:"Milan"},{001:"Istanbul"},{002:"Baku"}]
What is the best way to do this?
First things first:
[{000:"Milan"},{001:"Istanbul"},{002:"Baku"}]
is invalid JSON. Properties must be quoted like so:
[{"000":"Milan"},{"001":"Istanbul"},{"002":"Baku"}]
In order to achieve this output you could use a Dictionary<string, string> that the JavaScriptSerializer will serialize to the desired output. So simply call the ToDictionary extension method on your model in order to convert it to a dictionary:
Like that:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
var branches =
from p in getBranchs(AppSession.BranchID.Value)
select new { p.Code, p.Name };
var model = branches.ToDictionary(x => x.Code, x => x.Name);
return Json(new[] { model }, JsonRequestBehavior.AllowGet);
}
or if you want to keep your private method which returns an object you could make it return a dictionary:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
return Json(getBranchList(AppSession.BranchID.Value), JsonRequestBehavior.AllowGet);
}
private object getBranchList(int n)
{
var mybranchList = from p in getBranchs(n)
select new { p.Code, p.Name };
return new[] { mybranchList.ToDictionary(x => x.Code, x => x.Name) };
}
Notice that I used new[] { model }. That's because otherwise the JavaScriptSerializer won't produce a javascript array as required but a simple javascript object.
Remark: notice that I have added JsonRequestBehavior.AllowGet so that this controller action can be consumed with a GET request which is disabled by default for actions returning JSON responses.

Resources