While building a ASP.NET-MVC website I was trying to implement a EDIT page on my website, but I'm having some difficulties, particulary in my Controller. The error is in this class, pointing to the ID:
public IActionResult Edit(int ID = 0)
{
GestaoAlertas _teste = addresses.Contains(ID);
return View(_teste);
}
And the error says:
It is not possible to convert from int to "hdsportal.GestaoAlertas"
Controller:
public class HomeController : Controller
{
SqlCommand com = new SqlCommand();
SqlDataReader dr;
SqlConnection con = new SqlConnection();
List<GestaoAlertas> addresses = new List<GestaoAlertas>();
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
con.ConnectionString = "secret";
}
public IActionResult Gestao_Alertas()
{
FetchData();
return View(addresses);
}
[Route("")]
public IActionResult Index()
{
FetchData();
return View(addresses);
}
public IActionResult Edit(int ID = 0)
{
GestaoAlertas _teste = addresses.Contains(ID);
return View(_teste);
}
public IActionResult Privacidade()
{
return View();
}
public IActionResult Gestao_Utilizadores()
{
return View();
}
public IActionResult Contatos()
{
return View();
}
public IActionResult QuemSomos()
{
return View();
}
private void FetchData()
{
if (addresses.Count > 0)
{
addresses.Clear();
}
try
{
con.Open();
com.Connection = con;
com.CommandText = "SELECT [ID], [SYSTEM_NAME], [SYSTEM_STATUS], [SYSTEM_SHORTMSG] FROM [CORE_SYS_STATUS]";
dr = com.ExecuteReader();
while (dr.Read())
{
addresses.Add(new GestaoAlertas()
{
ID = (int)dr["ID"]
,
SYSTEM_NAME = dr["SYSTEM_NAME"].ToString()
,
SYSTEM_STATUS = dr["SYSTEM_STATUS"].ToString()
,
SYSTEM_SHORTMSG = dr["SYSTEM_SHORTMSG"].ToString()
});
}
con.Close();
}
catch (Exception ex)
{
throw ex;
}
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
Model:
public class GestaoAlertas
{
public int ID { get; set; }
public string SYSTEM_NAME { get; set; }
public string SYSTEM_STATUS { get; set; }
public string SYSTEM_SHORTMSG { get; set; }
}
Issue & Concern
According to List<T>.Contains(T), you need parse T object which is GestaoAlertas object to your addresses (List<GestaoAlertas> type).
Hence, you get the error below as it is an unmatched type with int
It is not possible to convert from int to "hdsportal.GestaoAlertas"
for this line:
GestaoAlertas _teste = addresses.Contains(ID);
And List<T>.Contains(T) returns the boolean result.
public bool Contains (T item);
Determines whether an element is in the List.
Solution(s)
Assumptions:
addresses contain GestaoAlertas records
You can get GestaoAlertas element from addresses by ID with either of these LINQ methods:
Pre-requisite:
Import System.Linq namespace.
using System.Linq;
Solution 1: Enumerable.SingleOrDefault
Returns a single, specific element of a sequence, or a default value if that element is not found.
Note: It will throw InvalidOperationException if input sequence contains more than one element. Good to be use for unique identifier such as ID.
GestaoAlertas _teste = addresses.SingleOrDefault(x => x.ID == ID);
Solution 2: Enumerable.Single
Returns a single, specific element of a sequence.
Note: It will throw ArgumentNullException if it returns null.
GestaoAlertas _teste = addresses.Single(x => x.ID == ID);
Solution 3: Enumerable.FirstOrDefault
Returns the first element of a sequence, or a default value if no element is found.
GestaoAlertas _teste = addresses.FirstOrDefault(x => x.ID == ID);
Solution 4: Enumerable.First
Returns the first element of a sequence.
Note: It will throw ArgumentNullException if it returns null.
GestaoAlertas _teste = addresses.First(x => x.ID == ID);
Related
enter image description here
First step...Opened WCF created IService:
namespace CRUDOperationWCFMVC
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService1
{
[OperationContract]
bool CreateDetails(EmployeeDetails employeeDetails);
[OperationContract]
bool UpdateDetails(EmployeeDetails employeeDetails);
[OperationContract]
bool DeleteDetails(int id);
[OperationContract]
List<EmployeeDetails> GetDetails();
}
public class EmployeeDetails
{
[DataMember]
public int EmpID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Location { get; set; }
[DataMember]
public int? Salary { get; set; }
}
}
Step 2: then I implemented service code:
public class Service1 : IService1
{
DataClasses1DataContext dcd = new DataClasses1DataContext();
public bool CreateDetails(EmployeeDetails employeeDetails)
{
Nevint emp = new Nevint();
emp.EmpID= employeeDetails.EmpID;
emp.Name = employeeDetails.Name;
emp.Location = employeeDetails.Location;
emp.Salary = employeeDetails.Salary;
dcd.Nevints.InsertOnSubmit(emp);
dcd.SubmitChanges();
return true;
}
public bool DeleteDetails(int id)
{
var delete = (from v in dcd.Nevints where v.EmpID==id select v).FirstOrDefault();
dcd.Nevints.DeleteOnSubmit(delete);
dcd.SubmitChanges();
return true;
}
public List<EmployeeDetails> GetDetails()
{
List<EmployeeDetails> details = new List<EmployeeDetails>();
var select= (from v in dcd.Nevints select v);
foreach (var i in select)
{
EmployeeDetails emp = new EmployeeDetails();
emp.EmpID = i.EmpID;
emp.Name = i.Name;
emp.Location = i.Location;
emp.Salary = i.Salary;
details.Add(emp);
}
return details;
}
public bool UpdateDetails(EmployeeDetails employeeDetails)
{
var update = (from v in dcd.Nevints.ToList() where employeeDetails.EmpID==v.EmpID select v).FirstOrDefault();
update.EmpID = employeeDetails.EmpID;
update.Name = employeeDetails.Name;
update.Location = employeeDetails.Location;
update.Salary = employeeDetails.Salary;
dcd.SubmitChanges();
return true;
}
}
Step 3: then I add linq to sql, opened my ASP.NET MVC project for consuming, and added a controller and wrote this code:
namespace ConsumingClient.Controllers
{
public class EmpdetailsController : Controller
{
ServiceReference1.Service1Client serobj=new ServiceReference1.Service1Client();
ServiceReference1.EmployeeDetails empdetails=new ServiceReference1.EmployeeDetails();
// GET: Empdetails
public ActionResult Index()
{
List<employee> lstemp = new List<employee>();
var result = serobj.GetDetails();
foreach (var i in result)
{
employee emp = new employee();
empdetails.EmpID = i.EmpID;
empdetails.Name = i.Name;
empdetails.Location = i.Location;
empdetails.Salary = i.Salary;
lstemp.Add(emp);
}
return View(result);
}
// GET: Empdetails/Details/5
public ActionResult Details(int id)
{
Employees emp = new Employees();
return View();
}
// GET: Empdetails/Create
public ActionResult Create()
{
return View();
}
// POST: Empdetails/Create
[HttpPost]
public ActionResult Create(Employees employees)
{
try
{
// TODO: Add insert logic here
empdetails.EmpID=employees.EmpID;
empdetails.Name = employees.Name;
empdetails.Location = employees.Location;
empdetails.Salary = employees.Salary;
serobj.CreateDetails(empdetails);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// GET: Empdetails/Edit/5
public ActionResult Edit(int id)
{
Employees emp = new Employees();
var result = serobj.GetDetails().FirstOrDefault(a=>a.EmpID==id);
emp.EmpID = result.EmpID;
emp.Name = result.Name;
emp.Location = result.Location;
emp.Salary = result.Salary;
return View(emp);
}
// POST: Empdetails/Edit/5
[HttpPost]
public ActionResult Edit(Employees employees)
{
try
{
// TODO: Add update logic here
empdetails.EmpID = employees.EmpID;
empdetails.Name = employees.Name;
empdetails.Location = employees.Location;
empdetails.Salary = employees.Salary;
serobj.UpdateDetails(empdetails);
return RedirectToAction("Index");
}
catch
{
return View(employees);
}
}
// GET: Empdetails/Delete/5
public ActionResult Delete(int id)
{
Employees emp = new Employees();
var result = serobj.GetDetails().FirstOrDefault(a=>a.EmpID==id);
emp.EmpID = result.EmpID;
emp.Name = result.Name;
emp.Location = result.Location;
emp.Salary = result.Salary;
return View(emp);
}
// POST: Empdetails/Delete/5
[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
try
{
// TODO: Add delete logic here
serobj.DeleteDetails(id);
return RedirectToAction("Index");
}
catch
{
return View(id);
}
}
}
}
Data was displaying fine. I can create data.
However, when I click on edit and delete, I'm getting an error:
ERROR Message "Server Error in '/' Application.
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Edit(Int32)' in 'ConsumingClient.Controllers.EmpdetailsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
This error is thrown if you attempt to call this controller action and you do not specify the id either in the path portion or as query string parameter. Since your controller action takes an id as parameter you should make sure that you always specify this parameter.
Make sure that when you are requesting this action you have specified a valid id in the url:
http://example.com/somecontroller/Edit/123
If you are generating an anchor, make sure there's an id:
#Html.ActionLink("Edit", "somecontroller", new { id = "123" })
If you are sending an AJAX request, also make sure that the id is present in the url.
If on the other hand the parameter is optional, you could make it a nullable integer:
public ActionResult Edit(int? id)
but in this case you will have to handle the case where the parameter value is not specified.
https://coderedirect.com/questions/197477/mvc-the-parameters-dictionary-contains-a-null-entry-for-parameter-k-of-non-n
public class HomeController : Controller
{
private readonly IUserDAService _user = DependencyResolver.Current.GetService<IUserDAService>();
public ActionResult About()
{
_user.GetAdminUser(1);
return View();
}
}
_user returns null. So _user.GetAdminUser(1) also gives System.NullReferenceException error.
public interface IUserDAService
{
int GetAdminUser(int id);
}
public class UserDAService : IUserDAService
{
public int GetAdminUser(int id)
{
using (var connection= DBConnection.CreateConnection())
{
connection.Open();
return connection.CacheQuery<int>(StoredProcedure.GetAdminUser, new { Id = id }, commandType: CommandType.StoredProcedure).FirstOrDefault();
}
}
}
I've seen a lot of similar posts on this, but haven't found the answer specific to controller parameters.
I've written a custom attribute called AliasAttribute that allows me to define aliases for parameters during model binding. So for example if I have: public JsonResult EmailCheck(string email) on the server and I want the email parameter to be bound to fields named PrimaryEmail or SomeCrazyEmail I can "map" this using the aliasattribute like this: public JsonResult EmailCheck([Alias(Suffix = "Email")]string email).
The problem: In my custom model binder I can't get a hold of the AliasAttribute class applied to the email parameter. It always returns null.
I've seen what the DefaultModelBinder class is doing to get the BindAttribute in reflector and its the same but doesn't work for me.
Question: How do I get this attribute during binding?
AliasModelBinder:
public class AliasModelBinder : DefaultModelBinder
{
public static ICustomTypeDescriptor GetTypeDescriptor(Type type)
{
return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = base.BindModel(controllerContext, bindingContext);
var descriptor = GetTypeDescriptor(bindingContext.ModelType);
/*************************/
// this next statement returns null!
/*************************/
AliasAttribute attr = (AliasAttribute)descriptor.GetAttributes()[typeof(AliasAttribute)];
if (attr == null)
return null;
HttpRequestBase request = controllerContext.HttpContext.Request;
foreach (var key in request.Form.AllKeys)
{
if (string.IsNullOrEmpty(attr.Prefix) == false)
{
if (key.StartsWith(attr.Prefix, StringComparison.InvariantCultureIgnoreCase))
{
if (string.IsNullOrEmpty(attr.Suffix) == false)
{
if (key.EndsWith(attr.Suffix, StringComparison.InvariantCultureIgnoreCase))
{
return request.Form.Get(key);
}
}
return request.Form.Get(key);
}
}
else if (string.IsNullOrEmpty(attr.Suffix) == false)
{
if (key.EndsWith(attr.Suffix, StringComparison.InvariantCultureIgnoreCase))
{
return request.Form.Get(key);
}
}
if (attr.HasIncludes)
{
foreach (var include in attr.InlcludeSplit)
{
if (key.Equals(include, StringComparison.InvariantCultureIgnoreCase))
{
return request.Form.Get(include);
}
}
}
}
return null;
}
}
AliasAttribute:
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class AliasAttribute : Attribute
{
private string _include;
private string[] _inlcludeSplit = new string[0];
public string Prefix { get; set; }
public string Suffix { get; set; }
public string Include
{
get
{
return _include;
}
set
{
_include = value;
_inlcludeSplit = SplitString(_include);
}
}
public string[] InlcludeSplit
{
get
{
return _inlcludeSplit;
}
}
public bool HasIncludes { get { return InlcludeSplit.Length > 0; } }
internal static string[] SplitString(string original)
{
if (string.IsNullOrEmpty(original))
{
return new string[0];
}
return (from piece in original.Split(new char[] { ',' })
let trimmed = piece.Trim()
where !string.IsNullOrEmpty(trimmed)
select trimmed).ToArray<string>();
}
}
Usage:
public JsonResult EmailCheck([ModelBinder(typeof(AliasModelBinder)), Alias(Suffix = "Email")]string email)
{
// email will be assigned to any field suffixed with "Email". e.g. PrimaryEmail, SecondaryEmail and so on
}
Gave up on this and then stumbled across the Action Parameter Alias code base that will probably allow me to do this. It's not as flexible as what I started out to write but probably can be modified to allow wild cards.
what I did was make my attribute subclass System.Web.Mvc.CustomModelBinderAttribute which then allows you to return a version of your custom model binder modified with the aliases.
example:
public class AliasAttribute : System.Web.Mvc.CustomModelBinderAttribute
{
public AliasAttribute()
{
}
public AliasAttribute( string alias )
{
Alias = alias;
}
public string Alias { get; set; }
public override IModelBinder GetBinder()
{
var binder = new AliasModelBinder();
if ( !string.IsNullOrEmpty( Alias ) )
binder.Alias = Alias;
return binder;
}
}
which then allows this usage:
public ActionResult Edit( [Alias( "somethingElse" )] string email )
{
// ...
}
I have a wizard step in which a user fills in fields. I then use json to save the values into my database for each wizard step.
However, in my repository I have my savechanges(). But it wont save the changes, instead it throws an error:
Entities in 'NKImodeledmxContainer.SelectedQuestion' participate in the 'QuestionSelectedQuestion' relationship. 0 related 'Question' were found. 1 'Question' is expected.
Anyone know how to get rid of the error? Do I have to get the ID from Question and save it aswell to my database or can I change something in EF so the error message is not getting thrown?
This is my post in my controller:
[HttpPost]
public JsonResult AnswerForm(int id, SelectedQuestionViewModel model)
{
bool result = false;
var goalCardQuestionAnswer = new GoalCardQuestionAnswer();
goalCardQuestionAnswer.SelectedQuestion = new SelectedQuestion();
goalCardQuestionAnswer.SelectedQuestion.Id = model.QuestionID;
goalCardQuestionAnswer.Comment = model.Comment;
goalCardQuestionAnswer.Grade = model.Grade;
if (goalCardQuestionAnswer.Grade != null)
{
answerNKIRepository.SaveQuestionAnswer(goalCardQuestionAnswer);
answerNKIRepository.Save();
result = true;
return Json(result);
}
answerNKIRepository.SaveQuestionAnswer(goalCardQuestionAnswer);
answerNKIRepository.Save();
return Json(result);
}
My Repository
public class AnswerNKIRepository
{
private readonly NKImodeledmxContainer db = new NKImodeledmxContainer();
public List<SelectedQuestion> GetAllSelectedQuestionsByGoalCardId(int goalCardId)
{
return db.SelectedQuestion.Where(question => question.GoalCard.Id == goalCardId).ToList();
}
public void SaveQuestionAnswer(GoalCardQuestionAnswer goalCardQuestionAnswer)
{
db.GoalCardQuestionAnswer.AddObject(goalCardQuestionAnswer);
}
public void Save()
{
db.SaveChanges();
}
}
This is my ViewModel:
public class SelectedQuestionViewModel
{
public int? Grade { get; set; }
public string Comment { get; set; }
public string SelectedQuestionText { get; set; }
public int QuestionID { get; set; }
}
This is my database model:
The exception complains that SelectedQuestion.Question is a required navigation property but you don't set this property in your code. Try to load the question by Id from the repository and set it to the SelectedQuestion.Question reference: Replace this line ...
goalCardQuestionAnswer.SelectedQuestion.Id = model.QuestionID;
...by...
goalCardQuestionAnswer.SelectedQuestion.Question =
answerNKIRepository.GetQuestionById(model.QuestionID);
And in your repository add the method:
public Question GetQuestionById(int id)
{
return db.Question.Single(q => q.Id == id);
}
My Html action link takes me to a view where i can see the details..
For Ex:http://localhost:1985/Materials/Details/4
But it shows error,
The model item passed into the dictionary is of type
'System.Data.Linq.DataQuery`1[CrMVC.Models.ConstructionRepository+Materials]'
but this dictionary requires a model item of type
'CrMVC.Models.ConstructionRepository+Materials'.
And my model is...
public IQueryable<Materials> GetMaterial(int id)
{
return from m in db.Materials
join Mt in db.MeasurementTypes on m.MeasurementTypeId equals Mt.Id
where m.Mat_id == id
select new Materials()
{
Id = Convert.ToInt64(m.Mat_id),
Mat_Name = m.Mat_Name,
Mes_Name = Mt.Name,
};
}
public class Materials
{
private Int64 id;
public string mat_Name;
public string mes_Name;
public Int64 Id
{
get
{
return id;
}
set
{
id = value;
}
}
public string Mat_Name
{
get
{
return mat_Name;
}
set
{
mat_Name = value;
}
}
public string Mes_Name
{
get
{
return mes_Name;
}
set
{
mes_Name = value;
}
}
}
}
and my controller method...
public ActionResult Details(int id)
{
var material = consRepository.GetMaterial(id).AsQueryable();
return View("Details", material);
}
Any suggestion what am i missing here?
Your GetMaterial(id) method should probably return just one Material instance because your View expects just one instance. E.g:
public Materials GetMaterial(int id)
{
return (from m in db.Materials
join Mt in db.MeasurementTypes on m.MeasurementTypeId equals Mt.Id
where m.Mat_id == id
select new Materials()
{
Id = Convert.ToInt64(m.Mat_id),
Mat_Name = m.Mat_Name,
Mes_Name = Mt.Name,
}).FirstOrDefault();
}