I'm looking for a solution for this for 2 days already and can't find the answer, everything I find doesn't work so I thought somebody here might help.
I have a chart that I've managed to call from View with Url.Action like this:
<img src="#Url.Action("DrawPieChart")"/>
but I don't know how to pass the value of the parameter(countryName) through Url.Action so I can pass it through controller and finally use it in AnalyzerData.class
Here is the controller: WebTrafficController
public class WebTrafficController : Controller
{
public ActionResult WebTraffic()
{
AnalzyerData analyzerData = new AnalzyerData();
//main actionResult that shows stuff not important for this question
return View(analyzerData);
}
public ActionResult DrawPieChart(string countryName)
{
AnalzyerData analyzerData = new AnalzyerData();
return PartialView(analyzerData.getChart(countryName));
}
}
Class: AnalyzerData
public class AnalzyerData
{
public Chart chartImg { get; set; }
public Chart getChart(string countryName)
{
cWebTrafficDb checkUserStatsWrapper = new cWebTrafficDb();
checkUserStatsWrapper.cmd.CommandText = string.Format("select user_browser, count(*) from user_stats where User_country = '{0}' group by user_browser", countryName);
//checkUserStatsWrapper.cmd.CommandText = string.Format("select user_browser, count(*) from user_stats group by user_browser");
MySqlDataReader reader = checkUserStatsWrapper.cmd.ExecuteReader();
List<object> result1 = new List<object>();
List<object> result2 = new List<object>();
while (reader.Read())
{
result1.Add(reader.GetString(0));
result2.Add(reader.GetString(1));
}
chartImg = new Chart(width: 350, height: 350)
.AddTitle("Naslov")
.AddSeries(
name: "Employee",
chartType: "Pie",
xValue: result1,
yValues: result2)
.Write();
return chartImg;
}
View: Webtraffic.cshtml
#model WebTraff.Models.AnalzyerData
#{
ViewBag.Title = "WebTraffic";
}
<div class="inline">
<img src="#Url.Action("DrawPieChart","countryName", new { countryName = "Croatia" })"/>
</div>
P.S. if this isn't possible please tell me how to do this, I've tried a few different methods and I couldn't get it work
There's one thing you can try here.
Replace this :
<img src="#Url.Action("DrawPieChart","WebTraffic", new { countryName = "Croatia" })"/>
With this :
<img src="#Url.Action("DrawPieChart","WebTraffic", new { #countryName = "Croatia" })"/>
Or you can also try it like this :
#Url.Action("DrawPieChart", "WebTraffic", new { #countryName = "Croatia" })
Try putting the # symbol before the parameter name and make sure the parameter name remains identical on both sides.
Hope this helps.
Not sure if this was ever resolved but I just came across the same issue. I found out that using your code of:
<img src="#Url.Action("DrawPieChart","countryName", new { countryName = "Croatia" })"/>
passed the browser the following html
<img src="/countryName/DrawPieChart?countryName=Croatia">
Changing your code by simply dropping the first "countryName" to match the following:
<img src="#Url.Action("DrawPieChart", new { countryName = "Croatia" })"/>
worked for me... Hope this helps!
Related
Dear Community Member(s)
Following a search online with regards to Binding country list using cultureinfo in ASP.NET Core MVC
updating the Controller thanks to the following codes did help:
List<string> CountryList = new List<string>() ;
CultureInfo[] CInfoList = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
foreach (CultureInfo CInfo in CInfoList)
{
RegionInfo R = new RegionInfo(CInfo.LCID);
if (!(CountryList.Contains(R.EnglishName)))
{
CountryList.Add(R.EnglishName);
}
}
CountryList.Sort();
ViewBag.CountryList = CountryList;
return View();
in conjunction with the following Tag Helper from View:
#Html.DropDownList("CountryList",new SelectList(ViewBag.CountryList), "Select a country", new
{#class = "form-control" })
However, I wonder how to Get/Read the value of a selected country, still via a Controller's method. I had in mind defining firstly
in Model a public property such as:
public IEnumerable <SelectListItem> countryList {
get;
set;
}
but I am keen on knowing a better way of achieving this via a Model.
N.B: In ASP.NET I used to achieving such request through:
string example = testid.SelectedItem.Text;
after adding an event to
<asp:DropDownList ID="testid" runat="server" CssClass="form-control"
OnSelectedIndexChanged="test_event" AppendDataBoundItems="true" AutoPostBack="true">
</asp:DropDownList>
Any relevant feedback would highly be appreciated.
N.B: The ideal solution shall involve defining CountryList (e.g. countrylist) in Model as a public property, so as to be able to retrieve any selected country via a Controller's method.
Best
If you want to get the selected value in controller,you can try to use a form,when the selected item change,pass the selected value to controller,here is a demo:
action:
public IActionResult TestCountryList(string CountryList)
{
List<string> countryList = new List<string>();
CultureInfo[] CInfoList = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
foreach (CultureInfo CInfo in CInfoList)
{
RegionInfo R = new RegionInfo(CInfo.LCID);
if (!(countryList.Contains(R.EnglishName)))
{
countryList.Add(R.EnglishName);
}
}
countryList.Sort();
ViewBag.CountryList = countryList;
return View();
}
TestCountryList View:
<form id="myform" method="post">
#Html.DropDownList("CountryList", new SelectList(ViewBag.CountryList), "Select a country", new
{ #class = "form-control" })
</form>
#section scripts
{
<script>
$("#CountryList").change(function () {
$("#myform").submit();
})
</script>
}
result:
I'm following this tutorial to create my own custom "blog" functionality, but instead of creating blog posts, it creates "projects" with a Title, Date Created, Short Description, Long Description, and Team Leader.
The following code is supposed to change a project's information if the int passed in the url matches its primary key, and if not, create a new project with all of the above parameters.
However, when it gets to model.SaveChanges (seen below), it throws an error.
I am aware that I'm working in MVC 5 and the tutorial is in MVC 3, but so far everything has translated relatively well.
Here is my Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SouthMeckNTHS.Models;
using SouthMeckNTHS.Extensions;
using System.Text;
namespace SouthMeckNTHS.Controllers
{
public class ProjectsController : Controller
{
private ProjectsModel model = new ProjectsModel();
// GET: Projects
public ActionResult Index()
{
return RedirectToAction("My");
}
[Authorize]
public ActionResult My()
{
return View();
}
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Update(int? id, string title, string shortDescription, string longDescription, DateTime dateTime, string technologies)
{
//REMEMBER TO ADD PROJECT LEADER FUNCTIONALITY!!
if (!User.IsInRole("ChapterAdvisor"))
{
RedirectToAction("Index");
}
Project project = GetProject(id);
project.Title = title;
project.ShortDescription = shortDescription;
project.LongDescription = longDescription;
project.TimeCreated = dateTime;
project.ProjectLeader = User.Identity.GetFirstName() + " " + User.Identity.GetLastName();
project.Technologies.Clear();
technologies = technologies ?? string.Empty;
string[] technologyNames = technologies.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
foreach (string technologyName in technologyNames)
{
project.Technologies.Add(GetTechnology(technologyName));
}
if (!id.HasValue)
{
model.Projects.Add(project);
}
try
{
model.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
// raise a new exception nesting
// the current instance as InnerException
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
return RedirectToAction("Details", new { id = project.Id });
}
[ValidateInput(false)]
public ActionResult Edit(int? id)
{
Project project = GetProject(id);
StringBuilder technologyList = new StringBuilder();
foreach (Technology technology in project.Technologies)
{
technologyList.AppendFormat("{0} ", technology.Name);
}
ViewBag.Technologies = technologyList.ToString();
return View(project);
}
private Technology GetTechnology(string technologyName)
{
return model.Technologies.Where(x => x.Name == technologyName).FirstOrDefault() ?? new Technology() { Name = technologyName };
}
private Project GetProject(int? id)
{
return id.HasValue ? model.Projects.Where(x => x.Id == id).First() : new Project() { Id = 0 };
}
[Authorize]
public ActionResult Join()
{
return View();
}
}
}
Here is the View:
#model SouthMeckNTHS.Models.Project
#using SouthMeckNTHS.Extensions;
#{
ViewBag.Title = "Edit";
}
<br />
<br />
<br />
<br />
<br /><br />
<form action="#Href("~/Projects/Update")" method="post" id="postForm">
#Html.AntiForgeryToken()
#if (Model.Id != 0)
{
<input type="hidden" name="id" value="#Model.Id" />
}
#{ DateTime dateTime = Model.TimeCreated.Year > 2000 ? Model.TimeCreated : DateTime.Now; }
<input type="text" name="dateTime" value="#dateTime" /> Date<br />
<input type="text" name="title" value="#Model.Title" /> Project Name<br />
#Html.DropDownListFor(m => m.Technologies, new SelectList(new List<Object> { new { value = "Animation", text = "Animation" }, new { value = "Robotics", text = "Robotics" }, new { value = "Architecture", text = "Architecture" }, new { value = "CAD", text = "CAD" }, new { value = "Websites", text = "Websites" }, new { value = "Games", text = "Games" }, new { value = "Biotechnology", text = "Biotechnology" }, new { value = "Club", text = "Club" }, new { value = "Other", text = "Other" } }, "value", "text"), new { #style = "border: 1px solid #e8e8e8;padding: 0.5em 1.07em 0.5em;background: #f5f5f5;font-size: 0.875rem;border-radius: 5px;width: 100%;line-height: 1.43;min-height: 3.5em;" })
<textarea name="shortDescription" rows="5" cols="80">#Model.ShortDescription</textarea><br />
<textarea name="longDescription" rows="10" cols="80">#Model.LongDescription</textarea><br />
<input type="submit" name="submit" value="Save Changes" />
</form>
**And THIS is the error I get:
Click Here to View the image
^The Image above is of the error reading:
Violation of PRIMARY KEY constraint 'PK__Projects__3214EC0766FE6300'. Cannot insert duplicate key in object 'dbo.Projects'. The duplicate key value is (0).
The statement has been terminated.
And the subsequent text after it.
Any ideas what is happening/how to fix it and why it is not working for me?
I don't understand why the tutorial's example doesn't throw the error about "duplicate keys" when mine is almost identitical.
I think ef is trying to attach the entity (adding it) instead of modifying it, that's I guess because your context is tracking the entity probably because of your call on get, try using find instead of first, because find
The Find method on DbSet uses the primary key value to attempt to find an entity tracked by the context. If the entity is not found in the context then a query will be sent to the database to find the entity there. Null is returned if the entity is not found in the context or in the database.
so you don't have this entity tracked while you are updating it, because you are updating the tracked one itself.
so in your GetProject, replace this
model.Projects.Where(x => x.Id == id).First()
with this
model.Projects.Find(id)
A PartialView contains a model Foo with a List<Bar>. Each Bar item contains two properties, BarA (string) and BarB (decimal).
I am trying to render a Chart in that partial view, but for that to work I need to call an action on the same Controller and pass the result to an <img /> element. To render the chart, I need the collections of BarA and BarB to format the data.
So I'm trying with something like this:
Controller
public void GenerateChart(List<Bar> model)
{
var chart = new System.Web.Helpers.Chart(400, 200)
.AddTitle("Title")
.AddSeries(
name : "name",
xValue : model.Select(m => m.BarA).ToArray(),
yValues : model.Select(m => m.BarB).ToArray())
.Write();
}
Partial View
RouteValueDictionary rvd = new RouteValueDictionary();
for (int i = 0; i < Model.Bars.Count; ++i)
{ rvd.Add("model[" + i + "]", Model.Bars[i]); }
<img src="#Url.Action("GenerateChart", rvd)" />
The problem with this is that even though the model object contains the three items it should contain, these are null.
I also tried to use the ViewBag, like this:
ViewBag.BarA = Model.Bars.Select(m => m.BarA).ToArray();
ViewBag.BarB = Model.Bars.Select(m => m.BarB).ToArray();
With this on the controller side
public void GenerateChart()
{
var chart = new System.Web.Helpers.Chart(400, 200)
.AddTitle("Title")
.AddSeries(
name : "name",
xValue : ViewBag.BarA,
yValues : ViewBag.BarB)
.Write();
}
But both arrays are null. I've also tried a few different ideas but I'm not able to get the information I need.
To triple-check (the data is shown fine in the view) that the data is correct, I changed to this:
#{
string[] barAs = Model.Select(m => m.BarA).ToArray();
decimal[] barBs = Model.Select(m => m.BarB).ToArray();
ViewBag.BarAs = barAs; // this has 3 items with the expected data
ViewBag.BarBs = barBs; // this also works
}
<img src="#Url.Action("GenerateChart")" />
string[] BarAs = ViewBag.BarAs; // this assigns null
decimal[] BarBs = ViewBag.BarBs; // this also assigns null
It seems you don't really understand how MVC works. I encourage you to spend some time going through all the tutorials at http://asp.net/mvc to familiarize yourself with the framework. Namely, it seems you're trying to approach a lot of this as if you were in the world of Web Forms. MVC is an entirely different beast.
First, Html.Action cannot return a full image, because all it's going to do is just dump the return value to the HTML being generated, and you can't embed a binary object directly in HTML.
Second, even if you could, you can't use that as the src for an img tag. The src must be a string, namely a URL, point to a location of an image.
So, in order to achieve this. You will need a full action that returns a proper response as an image. Then, you can simply link your image src to the route that hits this action.
public ActionResult GenerateChart(List<Bar> model)
{
var chart = new System.Web.Helpers.Chart(400, 200)
.AddTitle("Title")
.AddSeries(
name : "name",
xValue : model.Select(m => m.BarA).ToArray(),
yValues : model.Select(m => m.BarB).ToArray())
.GetBytes("jpeg");
return File(chart, "image/jpeg");
}
Then,
<img src="#Url.Action("GenerateChart", new { model = rvd })" alt="" />
Now, you're just link to a URL. That URL maps to a route that hits your GenerateChart action, which then returns an actual image - same as if you directly linked to a physical image. Now, the browser can properly render the img tag to the page.
Passing a complex type to actions via GET request is technically bloody thing so I do not know if this solution fits your needs you can follow up the method below;
Your action will recieve model as serialized string and you have to Deserialize it to your model
public ActionResult GenerateChart(string modelAsString)
{
List<Bar> model = new List<Bar>();
model = JsonConvert.DeserializeObject<List<Bar>>(modelAsString);
var chart = new System.Web.Helpers.Chart(400, 200)
.AddTitle("Title")
.AddSeries(
name: "name",
xValue: model.Select(m => m.BarA).ToArray(),
yValues: model.Select(m => m.BarB).ToArray())
.GetBytes("jpeg");
return File(chart, "image/jpeg");
}
Then you need to call your action via querystring like ?modelAsString={jsonData}
The example URL I use to process data : http://localhost:18681/Home/GenerateChart/?modelAsString=[{%22BarA%22:%22barAData%22,%22BarB%22:1.1},{%22BarA%22:%22barAData2%22,%22BarB%22:441.14},{%22BarA%22:%22barAData43%22,%22BarB%22:44.1}]
You should create your <img> URLs via serializing your model which ready on the page's action which you use <img>s.
I have tested a dummy data you can see output below;
PS: for creating dummy data I used the method below;
public ActionResult DummyData()
{
List<Bar> model = new List<Bar>();
model.Add(new Bar() { BarA = "barAData", BarB = 1.1m });
model.Add(new Bar() { BarA = "barAData2", BarB = 441.14m });
model.Add(new Bar() { BarA = "barAData43", BarB = 44.1m });
return Json(model, JsonRequestBehavior.AllowGet);
}
And I wonder too if any more efficient way to do this via get request.
Hope this helps!
I am wondering if anyone could help me, the problem I have is that I am trying to not show the parameter in URL, when the parameter is posted to another controller. I have tried routing and changing the ActionLink. If anyone one could help it would be greatly appreciated.
I get "/Accounts/ViewCustomer/Index/3316", I want to hide 3316
Customer list view
#Html.Grid(Model.CustomerList).Columns(columns =>
{
columns.Add(data => data.Referance).Titled("Reference").Sanitized(false).Encoded(false).Filterable(true).
RenderValueAs(model => Html.ActionLink(model.Referance, "Index", "ViewCustomer",
routeValues: new { id = model.CustomerID },
htmlAttributes: new { id = "cust" }).ToHtmlString());
columns.Add(data => data.Company).Titled("Company").Sanitized(false).Encoded(false).Filterable(true).
RenderValueAs(model => Html.ActionLink(model.Company, "Index", "ViewCustomer", new { id = model.CustomerID }, null).ToHtmlString());
}).WithPaging(#ViewBag.Pagesize, #ViewBag.PageCountLimit).Sortable()
From view customer Controller to which int is posted
public ActionResult Index(int? id)
{
Paging paginginfo = GridPageProvider.Pagesize();
ViewData["Pagesize"] = paginginfo.Pagesize;
ViewData["PageCountLimit"] = paginginfo.PageCountLimit;
SetCustomerInfo(id);
if (_customerdetail.Contacts.Count != 0)
{
return View( _customerdetail);
}
else
{
return RedirectToAction("Index", "Home");
}
}
In this case 3316 is part of your URL and you can't hide it. But you can send id as parameter (you will need change routing) and use POST method to hide it in method body
I am working in ASP.NET MVC 4 with C#, and i'm trying to turn the parameter of one ActionResult method into a variable for use in another method. So I have this for example:
public ActionResult Index(int ser)
{
var invoice = InvoiceLogic.GetInvoice(this.HttpContext);
// Set up our ViewModel
var pageViewModel = new InvoicePageViewModel
{
Orders = (from orders in proent.Orders
where orders.Invoice == null
select orders).ToList(),
Callouts = (from callouts in proent.Callouts
where callouts.Invoice == null
select callouts).ToList(),
InvoiceId = ser,
InvoiceViewModel = new InvoiceViewModel
{
InvoiceId = ser,
InvoiceItems = invoice.GetInvoiceItems(),
Clients = proent.Clients.ToList(),
InvoiceTotal = invoice.GetTotal()
}
};
// Return the view
return View(pageViewModel);
}
I need that int ser to somehow become "global" and its value become available to this method:
public ActionResult AddServiceToInvoice(int id)
{
return Redirect("/Invoice/Index/");
}
As you can see in my return statement just above, I get an error as I am not passing the variable "ser" back to Index, but I need it to be the same value that was passed to Index when the action was called. Can anyone assist?
When you construct your link to that method, you need to ensure you are passing your variable ser to the method along with any other parameters that it needs (it is unclear if the id in the AddServiceToInvoice method is actually the ser parameter or not. This assumes it is not)
Action Link In View
#Html.ActionLink("Add Service", "Invoice", "AddServiceToInvoice", new {id = IdVariable, ser = Model.InvoiceId})
AddServiceToInvoice Action Method
public ActionResult AddServiceToInvoice(int id, int ser)
{
//Use the redirect to action helper and pass the ser variable back
return RedirectToAction("Index", "Invoice", new{ser = ser});
}
You need to create a link with that ID:
if you're doing a get-request that would be something like this:
#Html.ActionLink("Add service to invoice", "Controller", "AddServiceToInvoice",
new {id = Model.InvoiceViewModel.InvoiceId})
Otherwise if you want to do a post you need to create a form:
#using Html.BeginForm(action, controller, FormMethod.Post)
{
<input type="hidden" value="#Model.InvoiceViewModel.InvoiceId" />
<input type="submit" value="Add service to invoice" />
}