ASP.NET MVC Bad Practices: Model With Optional and Required Properties - c#

When the code has been detected by Fortify Security with the above possible error.
I cannot understand how the models can be manipulated to avoid the possible error.
What sort of checks could be done to avoid the error ?
How do we determine if it is an actual error.
eg :
public class TestObject
{
public string ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string TestService { get; set; }
public int selected { get; set; }
public TestObject()
{
}
}
[HttpPost, ValidateAntiForgeryToken()]
public ActionResult TestObject DataModel, string command)
{
}
Since the TestObject has [Required] and not required attributes.Fortify could be raising the error.

Related

Converting infinitely nested objects in .NET Core

EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?

Error inheriting from generic base class in Xamarin.iOS

I'm developing a Xamarin.iOS application which will connect to a web service via a RESTful API. I am currently writing the response and business objects for the API client layer, but I have run into a problem.
Consider the following two sample API results:
Successful
{
"data":{
"id":"gwaMR",
"animated":false,
"size":11762,
"link":"http:\/\/i.imgur.com\/gwaMR.jpg"
},
"success":true,
"status":200
}
Erroneous
{
"data":{
"error":"Unable to find an image with the id, vycVV",
"request":"\/3\/image\/vycVV",
"method":"GET"
},
"success":false,
"status":404
}
Because both the successful data information as well as the error details both share the "data" key in their respective scenarios, I have written the following objects in C#:
public class BaseBusinessObject<D> where D:BaseBusinessObjectData
{
public D Data { get; set; }
public int Status { get; set; }
public bool Success { get; set; }
}
public class BaseBusinessObjectData
{
public string Error { get; set; }
public string Method { get; set; }
public string Request { get; set; }
}
public class ImageObject : BaseBusinessObject<ImageObjectData>
{
}
public class ImageObjectData : BaseBusinessObjectData
{
public string ID { get; set; }
public bool Animated { get; set; }
public int Size { get; set; }
public string Link { get; set; }
}
When making the API call (using automatic object deserialization with RestSharp), I provide the object type ImageObject as the expected result type. However, I'm not actually able to get that far yet. When attempting to compile those response object types, I get the following error:
/Users/willseph/GitHub/Repos/AppName/API/API.cs(46,255+): Error
CS0305: Using the generic type `AppName.BaseBusinessObject'
requires `1' type argument(s) (CS0305)
However, when I take this same code and bring it into a standard C# library (still within Xamarin Studio), it compiles just fine.
As a workaround, I am able to remove generics from my code by using hiding and a new Data member:
public class BaseBusinessObject
{
public BaseBusinessObjectData Data { get; set; }
public int Status { get; set; }
public bool Success { get; set; }
}
public class BaseBusinessObjectData
{
public string Error { get; set; }
public string Method { get; set; }
public string Request { get; set; }
}
public class ImageObject : BaseBusinessObject
{
public new ImageObjectData Data { get; set; }
}
public class ImageObjectData : BaseBusinessObjectData
{
public string ID { get; set; }
public string Link { get; set; }
public int Size { get; set; }
public bool Animated { get; set; }
}
This compiles fine and results in expected behavior. Does anyone have any insight on what may be causing this issue?
I tried adding a separate temporary file alongside my workaround containing the original erroneous classes (though renamed to not cause conflict), and it appears to be compiling.
I'm not sure what the issue was, but I suppose it was some strange fluke or anomaly caused by my computer.

Under posted model state always valid

I have an interesting issue. I have following model with required data annotation for some of the properties.
public class Consumer : MongoEntity
{
public Consumer()
{
Products = new List<Product>();
}
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
[Required]
public Location CurrentLocation { get; set; }
public List<Product> Products { get; set; }
}
Now in my web api controller I am accepting this as a parameter as show below:
[Route("")]
[ValidateModel]
public IHttpActionResult Post([FromBody]Consumer consumer)
{
try
{
if (ModelState.IsValid)
{
_consumerService.Create(consumer);
return Ok("User created sucessfully.");
}
return BadRequest("User object is not complete. It's missing mandatory fields");
}
catch
{
return InternalServerError(new Exception("Something went wrong while saving the data back to database."));
}
}
I am under the impression that if any of the required field of consumer model is null model state should be false, but it always return true. Web api only sets model state null when i send an empty body to the controller. Is there any logical explanation to this? Why web api don't take account of required properties of complex argument type?

Adding Entity with child entities to Redis server resulting System.StackOverflowException

I am working on ASP.NET MVC project with EF6 with Database First. I am trying to use Redis server to cache frequently used objects.
But i am getting problem in saving related entities (parent-child). For example following Author and Author_Book classes are parent-child and referencing to each other (Foreign-Key constraint in RDBMS)
public partial class Author
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Author_Book> Author_Book { get; set; }
}
public partial class Author_Book
{
public int Id { get; set; }
public int AuthorId { get; set; }
public string Title { get; set; }
public virtual Author Author { get; set; }
}
public partial class Customer
{
public int ID { get; set; }
public string CustomerName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
Querying and trying to store query result to Redis server as below
using (EFTestContext db = new EFTestContext())
{
var data = db.Authors.ToList();
redisClient.Set<List<Author>>("author", data);
}
Above line redisClient.Set.. resulting following Exception
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
However if i store Customer entity (which doesn't have child entities) into Redis server it work fine
using (EFTestContext db = new EFTestContext())
{
var customers = db.Customers.ToList();
redisClient.Set<List<Customer>>("customers", customers);
}
So my question is how to store complete entity (with childs) into redis server?
I followed [DataContract] / [DataMember] approach (As #oferzelig mentioned in comment). It is working fine and no longer raising that exception. I am describing it here so it could help someone else.
EF Database-first by default does not add [DataContract] / [DataMember] attributes, we need to modify T4 template for it. I did following modifications in Model template Model1.tt.
Added [DataContract] attribute before the line
<#=codeStringGenerator.EntityClassOpening(entity)#>
now it looks like
[DataContract]
<#=codeStringGenerator.EntityClassOpening(entity)#>
Added [DataMember] attribute before line
<#=codeStringGenerator.Property(edmProperty)#>
and it looks like
[DataMember]
<#=codeStringGenerator.Property(edmProperty)#>
We also need to generate [DataMember] attribute for one-to-many relationships (e.g. public virtual ICollection<Author_Book> Author_Book { get; set; } in question) but NOT for one-to-one (e.g. public virtual Author Author { get; set; } in question). To achieve it i added a new function in CodeStringGenerator class
public string NavigationProperty_NeedDataMember(NavigationProperty navProp)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0}",
navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("[DataMember]") : ""
);
}
and called it just before the line
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>
as below
<#=codeStringGenerator.NavigationProperty_NeedDataMember(navigationProperty)#>
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>
And finally modified UsingDirectives procedure to add System.Runtime.Serialization, as below
public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
? string.Format(
CultureInfo.InvariantCulture,
"{0}using System;{1}" +
"{2}" +
"{3}",
inHeader ? Environment.NewLine : "",
includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
includeCollections ? (Environment.NewLine + "using System.Runtime.Serialization;") : "",
inHeader ? "" : Environment.NewLine)
: "";
}
That all.
Now it is generating following classes and i no need to edit classes manually after each update.
[DataContract]
public partial class Author
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual ICollection<Author_Book> Author_Book { get; set; }
}
[DataContract]
public partial class Author_Book
{
[DataMember]
public int Id { get; set; }
[DataMember]
public int AuthorId { get; set; }
[DataMember]
public string Title { get; set; }
public virtual Author Author { get; set; }
}
Hope it will help someone else.

how to map from a domain model to a view model from MVC controller with AutoMapper

I am trying to figure out how AutoMapper works in creating a map from the domain model to the view model with a complex collection.
Within my domain model (Search.Domain) ,
I have the following:
namespace Search.Domain.Model
{
public class Result
{
public int SearchTime { get; set; }
public List<ResultDetails> Context { get; set; }
}
public class ResultDetails
{
public string Entity { get; set; }
public string Jurisdiction { get; set; }
public DateTime DateReported { get; set; }
public string Description { get; set; }
public DateTime DateEntered { get; set; }
public string AssociatedLink { get; set; }
public int Relevance { get; set; }
}
}
with the MVC project (Search.WebUI) I have the following:
namespace Search.WebUI.Models
{
public class ResultViewModel
{
public int SearchTime { get; set; }
public List<ResultDetails> Context { get; set; }
}
public class ResultDetails
{
public string Entity { get; set; }
public string Jurisdiction { get; set; }
public DateTime DateReported { get; set; }
public string Description { get; set; }
public DateTime DateEntered { get; set; }
public string AssociatedLink { get; set; }
public int Relevance { get; set; }
}
}
Within the controller (HomeController.cs)
namespace Search.WebUI.Controllers
{
public class HomeController : Controller
{
private ISearchResultManager sr = new ResultManager();
public ActionResult Index()
{
ResultViewModel searchresults;
var results = sr.GetSearchResults(5);
Mapper.CreateMap<Search.Domain.Model.Result, ResultViewModel>();
searchresults = Mapper.Map<Search.Domain.Model.Result, ResultViewModel>(results);
return View("Home", searchresults);
}
}
}
The error message that is being generated when run is:
Missing type map configuration or unsupported mapping.
Mapping types:
ResultDetails -> ResultDetails
Search.Domain.Model.ResultDetails -> Search.WebUI.Models.ResultDetails
Destination path:
ResultViewModel.Context.Context.Context0[0]
Source value:
Search.Domain.Model.ResultDetails
In looking at this it appears that the nested List<ResultDetails> is causing an issue but I don't know what I am supposed to do to handle this type of mapping.
Is it correct to go all the way back into the domain for reference to the type? This seems as if I am pulling the domain into the UI which I would not want to do?
Is there another option for mapping domain models to view models in the UI? Basically I was hoping to have a view model within the UI that I could extend beyond the domain model for UI purposes and not put a reference to the domain model.
I am new to autoMapper so this entire thing may be wrong? I would appreciate any suggestions or guidance.
AutoMapper doesn't look at all potential child mapping when mapping a containing class. You need to explicitly add a mapping for the ResultDetails as well:
Mapper.CreateMap<Search.Domain.Model.Result.ResultDetails,
Search.WebUI.Models.ResultDetails>();

Categories