ASP.NET MVC Create method null int [duplicate] - c#

This question already has answers here:
How to convert C# nullable int to int
(20 answers)
Closed 8 years ago.
Hi my create method receives an int how can I allow this to be null-able? So I can use this method without the int sometimes.
public ActionResult Create(int id)
{
var model = new Job { IncidentID = id };
ViewBag.ActionCode = new SelectList(db.ActionTypes, "ActionCode", "ActionCode");
return View(model);
}
Obviously I've tried
(int ? id)
but then here it is not happy as it cant convert int? to int here :
var model = new Job { IncidentID = id };

try this
public ActionResult Create(int? id)
{
var model = new Job { IncidentID = id.GetValueOrDefault(0) };
//or var model = new Job { IncidentID = (int.parse(id) };
ViewBag.ActionCode = new SelectList(db.ActionTypes, "ActionCode", "ActionCode");
return View(model);
}
GetValueOrDefault(0) helps to assigns zero if id has no value or null
or
try this
var model = new Job { IncidentID = id.HasValue ? id.Value : 0 };

Just check if id has value and assign IncidentID only if it has:
public ActionResult Create(int? id)
{
var job = new Job();
if (id.HasValue)
job.IncidentID = id.Value;
ViewBag.ActionCode = new SelectList(db.ActionTypes, "ActionCode", "ActionCode");
return View(job);
}

You may use nullable int as your method parameter. Nullable<T> has a HasValue method which check whether a value has been assigned to the nullable variable. If it returns true, use the Value property to get the value of the variable.
public ActionResult Create(int? id)
{
var model=new Job();
if(id.HasValue)
{
model.IncidentID=id.Value;
}
//to do :return something
}

Related

Best way to append query string parameter to URL from object

I have query string class.
public class PagingModel
{
public int PageNumber { get; set; } = 1;
public string Filter { get; set; } = "text";
}
string url = "Menu/GetMenus";
I have to generate the URI with a query string based on an object in ASP.NET Core 5 preview. Is there any built in query helper?.
Required output:
/Menu/GetMenus?PageNumber=3&Filter=text
MVC Controller:
public async Task<IActionResult> index_partial([FromQuery] PagingModel paging)
{
var data = await _apiService.GetMenusAsync(paging);
return PartialView("_IndexPartial", data);
}
Service:
public async Task<PagedList<MenuModel>> GetMenusAsync(PagingModel paging)
{
string Requiredurl = "Menu/GetMenus?page="+ paging.PageNumber;
}
I got this extension method.. No need to generate query string manually.Only class object we need to pass. i thought some one else can use the same thing ...
public static string AppendObjectToQueryString(string uri, object requestObject)
{
var type = requestObject.GetType();
var data = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToDictionary
(
p => p.Name,
p => p.GetValue(requestObject)
);
foreach (var d in data)
{
if (d.Value == null)
{
continue;
}
if ((d.Value as string == null) && d.Value is IEnumerable enumerable)
{
foreach (var value in enumerable)
{
uri = QueryHelpers.AddQueryString(uri, d.Key, value.ToString());
}
}
else
{
uri = QueryHelpers.AddQueryString(uri, d.Key, d.Value.ToString());
}
}
return uri;
}
Ex: In my case i called this way.
string uri = "Menu/GetMenus";
string full_uri = QueryStringExtension.AppendObjectToQueryString(uri, paging);
With a Query String this simple I would just do
PagingModel qsData = new PagingModel();
//set qsData properties as needed
string urlWithQueryString = $"/Menu/GetMenus?{nameof(PagingModel.PageNumber)}={qsData.PageNumber}&nameof(PagingModel.Filter)}={qsData.Filter}";
However more standard is to do something like
string urlWithQueryString = this.Url.Action("GetMenus", "Menu", new PagingModel { PageNumber = 3, Filter = "text" }, this.Request.Url.Scheme);
But best solution depends on your specific case - can you add your action method definition for GetMenus ?
Update for your additional code :
Seeing as looks like you want to generate the url inside the service I would simply do this :
public async Task<PagedList<MenuModel>> GetMenusAsync(PagingModel paging)
{
string Requiredurl = $"/Menu/GetMenus?{nameof(PagingModel.PageNumber)}={paging.PageNumber}&nameof(PagingModel.Filter)}={paging.Filter}";
}

Get the largest Value from table unless null

I'm quite new to C# and ASP.NET (and programming in general) and try to do some simple exercises.
What I am trying to do:
I would like to build a simple MVC App where records will have versions.
That is: Given a record, that I am about to change via the "Edit"-View, this record will not be overwritten. Instead a new record will be created (like a new Version). Both, the old and new record, have the same ItemId (which is not the primary key!), that links them together "semantically". In order to know, which record is the newer Version, the newer record has a VersionId that is +1 the VersionId of the older one.
Currently: I've started working on the Create-Action. A new record shall get a value of 1 for it's VersionId and for ItemId the largest ItemId already in the DB plus 1 - unless there is no record in the DB in which case ItemId shall be 1.
The Model:
namespace HowToUpdate.Models
{
public class ItemWithVersion
{
public int Id { get; set; }
public int ItemNr { get; set; }
public int VersionNr { get; set; }
public string Name { get; set; }
}
}
The Controller Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name")] ItemWithVersion itemWithVersion)
{
if (ModelState.IsValid)
{
// set the ItemNr
int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
itemWithVersion.ItemNr = currentMaxItemNr + 1;
// set the VersionNr
itemWithVersion.VersionNr = 1;
db.ItemWithVersions.Add(itemWithVersion);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(itemWithVersion);
}
Problem: When I run localhost/ItemWithVersion/Create, enter a Value for the Name and Submit, i get the following error:
"The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
Source error: int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);"
I tried:
// set the ItemNr
int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
if (currentMaxItemNr == null)
{
itemWithVersion.ItemNr = 1;
}
else
{
itemWithVersion.ItemNr = currentMaxItemNr + 1;
}
Now the error seems to be int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
Also int? currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr); and var currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr); won't do any good.
It's probably basic but I need your help! :) Thx.
Your if-statement is wrong:
if (currentMaxItemNr != null)
currently checks if currentMaxItemNr has a value and if it does, make it 1
So your statement should be if (currentMaxItemNr == null)
Edit:
I can't replicate your error unfortunately, but I did check and found out that there's an exception thrown when calling Max() on an empty List. So it would be better to first call if (db.ItemWithVersions.Count() > 0)
That way you are sure that Max() will return a result. If it fails that statement, you can set currentMaxItemNr to 0
You need to make sure that your table is not empty before calling the Max() method. You can use the Any() method to do that.
int currentMaxItemNr = 0;
if (db.ItemWithVersions.Any())
{
currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
}
itemWithVersion.ItemNr = currentMaxItemNr + 1;
// set the VersionNr
itemWithVersion.VersionNr = 1;
db.ItemWithVersions.Add(itemWithVersion);
db.SaveChanges();
Probably, the reason is that Id is declared as a int (not nullable, so null can not be assigned to id) . Try following.
public int? Id { get; set; }
Care to try?
int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr ?? 1);
This will return currentMaxItemNr = 1 if your i.ItemNr is null.
here is how I would do this. When you click on Edit we run:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name")] ItemWithVersion itemWithVersion)
{
if (ModelState.IsValid)
{
// get the item with highest version
ItemWithVersion item = db.ItemWithVersions.Where(i =>i.ItemNr == itemWithVersion.ItemNr).OrderByDescending(i => i.VersionNr).FirstOrDefault();
//if item doesnt exist we need to create
if(item == null) {
//get the last item with highest ItemNr
ItemWithVersion lastitem = db.ItemWithVersions.OrderByDescending(i => i.ItemNr).FirstOrDefault();
if(lastitem == null) {
//if we didnt find a item, it means is the first item in the DB
itemWithVersion.ItemNr = 1;
} else {
//increment the itemNr for the new Item
itemWithVersion.ItemNr = lastitem.ItemNr + 1;
}
//set version to 1 since is the first version for this new ItemNr
itemWithVersion.VersionNr = 1;
} else {
//if we found a item for the current ItemNr we increase the version for the new item
itemWithVersion.VersionNr = item.VersionNr + 1;
}
db.ItemWithVersions.Add(itemWithVersion);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(itemWithVersion);
}

Lose MongoDB ObjectId value when passing through Actions

In my MVC Controller, I have this code (after adding an object, I redirect user to edit that object):
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Add()
{
MongoDataContext dc = new MongoDataContext();
var model = new ModelObj();
dc.Models.Insert(model);
return this.RedirectToAction("Edit", new { pId = model.Id, });
}
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Edit(ObjectId? pId)
{
MongoDataContext dc = new MongoDataContext();
var model = dc.Models.FindOneById(pId);
if (model == null)
{
Session["error"] = "No model with this ID found.";
return this.RedirectToAction("");
}
return this.View(model);
}
However, pId is always null, making the FindOneById always return null. I have debugged and made sure that the Id had value when passing from Add Action. Moreover, I tried adding a testing parameter:
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Add()
{
MongoDataContext dc = new MongoDataContext();
var model = new ModelObj();
dc.Models.Insert(model);
return this.RedirectToAction("Edit", new { pId = model.Id, test = 10 });
}
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Edit(ObjectId? pId, int? test)
{
MongoDataContext dc = new MongoDataContext();
var model = dc.Models.FindOneById(pId);
if (model == null)
{
Session["error"] = "No model with this ID found.";
return this.RedirectToAction("");
}
return this.View(model);
}
When I debug, I received the test parameter in Edit Action with value of 10 correctly, but pId is null. Please tell me what I did wrong, and how to solve this problem?
I would suspect that the ObjectId is not serializing/deserializing correctly. Given that it doesn't make for a great WebAPI anyway, I generally use a string and convert within the method to an ObjectId via the Parse method (or use TryParse):
public ActionResult Edit(string id, int? test)
{
// might need some error handling here .... :)
var oId = ObjectId.Parse(id);
}
You can use ToString on the ObjectId to convert it to a string for calling:
var pId = model.Id.ToString();

Hardcoded JsonpResult values

I have the following controller action:
[HttpGet]
public JsonpResult getTestValues(int? entityId, int? id)
{
return JsonpResult(WebResult.Success());
}
I have a AJAX call that invokes this controller and has to parse the data object returned. How can I modify the above to return the following?
{"data":[{"T1":"t1#test.com","T11":"1234-1234-1234-1234"},
{"T2":"t2#test.com","T22":"1234-1234-1234-1234"}]}
I need this for testing the UI framework that I am working on. Any suggestions on how to return the above hardcoded data?
Yes, you can do this using an anonymous type:
return JsonpResult {
Data = new {
data = new List<object> {
new { T1 = "t1#test.com", T11 = "1234-1234-1234-1234" },
new { T2 = "t2#test.com", T22 = "1234-1234-1234-1234" },
}
}
};

Get list of related objects whose type is in array of types

I have a function that (via ajax) I pass a Guid and a comma delimited string of the types of objects I would like to return . I'm having trouble building a link statement that only returns the desired types. I'm struggling with how to build the query to check if string[] relatedTypes matches rw.GetType().Name. Or perhaps there's a better way.
Here's the Model...
public abstract class WebObject : IValidatableObject
{
public WebObject()
{
this.Id = Guid.NewGuid();
RelatedTags = new List<Tag>();
RelatedWebObjects = new List<WebObject>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public virtual ICollection<WebObject> RelatedWebObjects { get; set; }
public IList<Guid> RelatedWebObjectIds { get; set; }
}
And here's my function
public JsonResult GetRelatedWebObjectsByWebObject(Guid id, string relatedWebObjectTypes)
{
JsonResult result = new JsonResult();
Guid webSiteId = db.WebObjects.Find(id).WebSiteId;
string[] relatedTypes = relatedWebObjectTypes.Split(',');
var resultData = (from w in db.WebObjects
where w.Id == id
from rw in w.RelatedWebObjects
where rw.GetType().Name.Contains(relatedTypes)
select rw.Id).ToList();
result.Data = resultData;
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return result;
}
Are you looking for something like:
var relatedTypes = new HashSet<string>(relatedWebObjectTypes);
var resultData = (from w in db.WebObjects
where w.Id == id
&& relatedTypes.SetEquals
(w.RelatedWebObjects.Select(rwo => rwo.GetType().Name))
select w.RelatedWebObjectIds).ToList();
Although I would say that it isn't good practice to use a collection of simple type names in this manner. Are you sure you couldn't use a Type[] or similar here?
It's not clear from your question what exactly do you want, but I think it's this:
from w in db.WebObjects
where w.Id == id
from rw in w.RelatedWebObjects
where relatedWebObjectTypes.Contains(rw.GetType().Name)
select rw.Id
This selects all the items from WebObjects with the correct Id (I guess there should be only one, but it does not matter to the query). And for each of them, get the RelatedWebObjects whose type's name is in relatedWebObjectTypes. And for each of those, get their Id.
You would need to refactor a bit, instead of passing in the name of the types as string, you should pass the actual type then use the linq operator for OfType(Of relatedType)
The MSDN Article gives a simple example that should have you on your way.
A little late, but here's what I ended up going with...
public JsonResult GetRelatedWebObjectsByWebObject(Guid id, string relatedWebObjectTypes)
{
JsonResult result = new JsonResult();
Guid webSiteId = db.WebObjects.Find(id).WebSiteId;
List<string> relatedTypes = new List<string>(relatedWebObjectTypes.Split(','));
var resultData = (from w in db.WebObjects
where w.Id == id
from rw in w.RelatedWebObjects
select rw).ToList();
result.Data = resultData.Where(w => relatedTypes.Contains(w.GetType().BaseType.Name) == true).Select(w => new { Id = w.Id, Type = w.GetType().BaseType.Name }).ToList();//w.Id).Select(w => w.GetType().BaseType.Name).ToList();
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return result;
}

Categories