Binding application/json to POCO object in asp.net mvc, Serialization exception - asp.net-mvc

I'm passing json back up from my view to my controller actions to perform operations. To convert the json being sent in, to a POCO I'm using this Action Filter:
public class ObjectFilter : ActionFilterAttribute {
public Type RootType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) {
IList<ErrorInfo> errors = new List<ErrorInfo>();
try {
object o = new DataContractJsonSerializer(RootType).ReadObject(filterContext.HttpContext.Request.InputStream);
filterContext.ActionParameters["postdata"] = o;
}
catch (SerializationException ex) {
errors.Add(new ErrorInfo(null, ex.Message));
}
finally {
filterContext.ActionParameters["errors"] = errors.AsEnumerable();
}
}
It's using the DataContractJsonSerializer to map the JSON, over to my object. My Action is then decorated like so:
[ObjectFilter(RootType = typeof(MyObject))]
public JsonResult updateproduct(MyObject postdata, IEnumerable<ErrorInfo> errors) {
// check if errors has any in the collection!
}
So to surmise, what is going on here, if there is a problem serializing the JSON to the type of object (if a string cannot be parsed as a decimal type or similar for eg), it adds the error to a collection and then passes that error up to the view. It can then check if this collection has an errors and report back to the client.
The issue is that I cannot seem to find out which field has caused the problem. Ideally I'd like to pass back to the view and say "THIS FIELD" had a problem. The SerializationException class does not seem to offer this sort of flexibility.
How would the collective SO hivemind consider tackling this problem?

I would just do an ajax form post. It's much easier.
http://plugins.jquery.com/project/form
http://malsup.com/jquery/form/

How about this: Json.Net
It reads a JSON string and then Deserialises it to the given POCO object.
string jsonResult = GetJsonStringFromSomeService();
MyPocoObject myobject = JsonConvert.DeserializeObject<MyPocoObject>(jsonResult);
Console.Write("Damn that is easy");
But for the determing where errors occur, I am not too sure.

Related

Returning Json from an MVC controller that extends Apicontroller

I'm trying to return a Json string from an MVC controller in a WebAPI application, but am unable to use return Json(... because the class being used extends ApiController and not Controller (I believe).
Is there an alternative method to do what I'm trying to do (e.g. return a different type)? Or a workaround?
This is my controller code:
public class SocialController : ApiController
{
public ActionResult Get(SocialRequest request) // or JsonResult?
{
JavaScriptSerializer js = new JavaScriptSerializer();
string jsontest = js.Serialize(request); // just serializing back and forth for testing
return Json(jsontest, JsonRequestBehavior.AllowGet);
}
}
The error I'm receiving is "System.Web.Helpers.Json is a type but is used like a variable."
I've found the following related SO question but it hasn't solved it for me, if anyone can elaborate I'd really appreciate it (and dish out the rep points):
Why Json() Function is unknown
In Asp.net Web Api you don't have ActionResults anymore. You simply return the object you need. The framework converts the object to the proper response (json, xml or other types)
[HttpGet]
public IEnumerable<string> GetUsers(SocialRequest request)
{
return _applicationsService.GetUserss(request);
}

How can I get the raw JSON dictionary from ASP.NET MVC Web API post?

With a ApiController subclass, it has the ability in Post method to bind it to an existing model object such as
public class RegisterController : ApiController
{
public void Post(Product product)
but if the incoming JSON data contains data that I'll use to create multiple model objects, how can I get to the data directly?
public void Post(dynamic value)
returns value as null. Is there an easy shorthand way of getting to it like request.POST['name'] or something?
Let's say the data looks like
{
'productID':1,
'productName':'hello',
'manufacturerID':1,
'manufacturerName':'world'
}
One option may be using one of the ReadAsAsync* methods in HttpContent instance off of the Request object
public void Post() {
var result = this.Request.Content.ReadAsAsync<string>().Result;
}
I don't know what format you're sending your data in, but you can retrieve it this way.
You could try this too for multiple objects...
public void Post(IEnumberable<Product> products) {
}

Access the error message in ModelState error dictionary in ASP.net MVC unit test

I have added a key-value pair in the action result like this:
[HttpPost, Authorize]
public ActionResult ListFacilities(int countryid)
{
...
ModelState.AddModelError("Error","No facilities reported in this country!");
...
}
I have some cumbersome codes like these in a unit test to :
public void ShowFailforFacilities()
{
//bogus data
var facilities = controller.ListFacilities(1) as PartialViewResult;
Assert.AreSame("No facilities reported in this country!",
facilities.ViewData.ModelState["Error"].Errors.FirstOrDefault().ErrorMessage);
}
Of course, it works whenever I have only one error.
I don't like facilities.ViewData.ModelState["Error"].Errors.FirstOrDefault().ErrorMessage.
Is there an easier way for me to fetch the value from that dictionary?
Your FirstOrDefault isn't needed, because you'll get a NullReferenceException when accessing ErrorMessage. You can just use First().
Either way, I couldn't find any built-in solution. What I've done instead is create an extension method:
public static class ExtMethod
{
public static string GetErrorMessageForKey(this ModelStateDictionary dictionary, string key)
{
return dictionary[key].Errors.First().ErrorMessage;
}
}
Which works like this:
ModelState.GetErrorMessageForKey("error");
If you need better exception handling, or support for multiple errors, its easy to extend...
If you want this to be shorter you can create an extension method for the ViewData...
public static class ExtMethod
{
public static string GetModelStateError(this ViewDataDictionary viewData, string key)
{
return viewData.ModelState[key].Errors.First().ErrorMessage;
}
}
and usage:
ViewData.GetModelStateError("error");
Have you tried this?
// Note: In this example, "Error" is the name of your model property.
facilities.ViewData.ModelState["Error"].Value
facilities.ViewData.ModelState["Error"].Error

Iterating over an unknown IQueryable's properties?

Forgive me if this has been asked before; I couldn't find anything close after a few searches:
I'm trying to write an ActionFilter in MVC that will "intercept" an IQueryable and nullify all the parent-child relationships at runtime. I'm doing this because Linq does not serialize objects properly if they have parent-child relationships (it throws a circular reference error because the parent refers to the child, which refers back to the parent and so on), and I need the object serialized to Json for an Ajax call. I have tried marking the child relationship in the DBML file with a privacy status of internal, and while this fixes the serialization problem, it also hides the child members from the view engine when the page renders, causing another error to be thrown. So, by fixing one problem, I cause another.
The only thing that fixes both problems is to manually set the child members to null just before returning the serialization, but I'm trying to avoid doing that because it's cumbersome, not reusable, etc. I'd rather use an ActionFilter to inspect the IQueryable that is being serialized and nullify any members with a Type of EntitySet (how Foreign Keys/Associations are represented). However, I don't have much experience with Reflection and can't find any examples that illustrate how to do something like this. So... is this possible with Reflection? Is there a better way to accomplish the same thing? I'll post the relevant code tomorrow when I'm back at my work computer.
Thanks,
Daniel
As promised, the code:
[GridAction]
public ActionResult _GetGrid()
{
IQueryable<Form> result = formRepository.GetAll();
foreach (Form f in result)
{
f.LineItems = null;
f.Notes = null;
}
return View(new GridModel<Form> { Data = result });
}
An added wrinkle is that I'm using the new Telerik MVC Extensions, so I'm not actually serializing the Json myself -- I'm just returning the IQueryable in an IGridModel, and the action filter [GridAction] does the rest.
So, just in case anyone's curious, here's how I finally solved this problem: I modified Damien Guard's T4 template to include the attribute [ScriptIgnore] above entities of type Association. This lets the JSON serializer know to not bother serializing these, thus preventing the circular reference problem I was getting. The generated code ends up looking like this:
private EntitySet<LineItem> _LineItems;
[ScriptIgnore]
[Association(Name=#"Form_LineItem", Storage=#"_LineItems", ThisKey=#"Id", OtherKey=#"FormId")]
public EntitySet<LineItem> LineItems
{
get {
return _LineItems;
}
set {
_LineItems.Assign(value);
}
}
This fixes the serialization problem I was having without disabling the use of child tables through LINQ. The grid action on the controller ends up looking like this:
[GridAction]
public ActionResult _GetGrid()
{
return View(new GridModel<Form> { Data = formRepository.GetAll() });
}
There are two options, one is to ignore those properties during serialization using [XmlIgnore]. The other one is to nullify the properties using reflection.
Ignore in serialization, simple usage sample that shows how to use default value in serialization:
[Serializable]
public class MyClass
{
[XmlIgnore]
public int IgnoredVal { get; set; }
public int Val { get; set; }
}
public void UsageSample()
{
var xmlSerializer = new XmlSerializer(typeof(MyClass));
var memoryStream = new MemoryStream();
var toSerialize = new MyClass { IgnoredVal = 1, Val = 2 };
xmlSerializer.Serialize(memoryStream, toSerialize);
memoryStream.Position = 0;
var deserialize = (MyClass)xmlSerializer.Deserialize(memoryStream);
Assert.AreEqual(0, deserialize.IgnoredVal);
Assert.AreEqual(2, deserialize.Val);
}
Nullify with reflection, code sample:
public void NullifyEntitySetProperties(object obj)
{
var entitySetProperties = obj.GetType().GetProperties()
.Where(property => property.PropertyType == typeof(EntitySet));
foreach (var property in entitySetProperties)
{
property.SetValue(obj, null, null);
}
}
In my opinion, if the first option can be done used in your code it's better. This option is more direct and economic.

Using Stored Procedures with Linq To Sql which have Additional Parameters

I have a very big problem and can't seem to find anybody else on the internet that has my problem. I sure hope StackOverflow can help me...
I am writing an ASP.NET MVC application and I'm using the Repository concept with Linq To Sql as my data store. Everything is working great in regards to selecting rows from views. And trapping very basic business rule constraints. However, I'm faced with a problem in my stored procedure mappings for deletes, inserts, and updates. Let me explain:
Our DBA has put a lot of work into putting the business logic into all of our stored procedures so that I don't have to worry about it on my end. Sure, I do basic validation, but he manages data integrity and conflicting date constraints, etc... The problem that I'm faced with is that all of the stored procedures (and I mean all) have 5 additional parameters (6 for inserts) that provide information back to me. The idea is that when something breaks, I can prompt the user with the appropriate information from our database.
For example:
sp_AddCategory(
#userID INT,
#categoryName NVARCHAR(100),
#isActive BIT,
#errNumber INT OUTPUT,
#errMessage NVARCHAR(1000) OUTPUT,
#errDetailLogID INT OUTPUT,
#sqlErrNumber INT OUTPUT,
#sqlErrMessage NVARCHAR(1000) OUTPUT,
#newRowID INT OUTPUT)
From the above stored procedure, the first 3 parameters are the only parameters that are used to "Create" the Category record. The remaining parameters are simply used to tell me what happened inside the method. If a business rule is broken inside the stored procedure, he does NOT use the SQL 'RAISEERROR' keyword when business rules are broken. Instead, he provides information about the error back to me using the OUTPUT parameters. He does this for every single stored procedure in our database even the Updates and Deletes. All of the 'Get' calls are done using custom views. They have all been tested and the idea was to make my job easier since I don't have to add the business logic to trap all of the various scenarios to ensure data quality.
As I said, I'm using Linq To Sql, and I'm now faced with a problem. The problem is that my "Category" model object simply has 4 properties on it: CategoryID, CategoryName, UserId, and IsActive. When I opened up the designer to started mapping my properties for the insert, I realized that there is really no (easy) way for me to account for the additional parameters unless I add them to my Model object.
Theoretically what I would LIKE to do is this:
// note: Repository Methods
public void AddCategory(Category category)
{
_dbContext.Categories.InsertOnSubmit(category);
}
public void Save()
{
_dbContext.SubmitChanges();
}
And then from my CategoryController class I would simply do the following:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
var category = new Category();
try
{
UpdateModel(category); // simple validation here...
_repository.AddCategory(category);
_repository.Save(); // should get error here!!
return RedirectToAction("Index");
}
catch
{
// manage friendly messages here somehow... (??)
// ...
return View(category);
}
}
What is the best way to manage this using Linq to Sql? I (personally) don't feel that it makes sense to have all of these additional properties added to each model object... For example, the 'Get' should NEVER have errors and I don't want my repository methods to return one type of object for Get calls, but accept another type of object for CUD calls.
Update: My Solution! (Dec. 1, 2009)
Here is what I did to fix my problem. I got rid of my 'Save()' method on all of my repositories. Instead, I added an 'Update()' method to each repository and actually commit the data to the database on each CUD (ie. Create / Update / Delete) call.
I knew that each stored procedure had the same parameters, so I created a class to hold them:
public class MySprocArgs
{
private readonly string _methodName;
public int? Number;
public string Message;
public int? ErrorLogId;
public int? SqlErrorNumber;
public string SqlErrorMessage;
public int? NewRowId;
public MySprocArgs(string methodName)
{
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("methodName");
_methodName = methodName;
}
public string MethodName
{
get { return _methodName; }
}
}
I also created a MySprocException that accepts the MySprocArgs in it's constructor:
public class MySprocException : ApplicationException
{
private readonly MySprocArgs _args;
public MySprocException(MySprocArgs args) : base(args.Message)
{
_args = args;
}
public int? ErrorNumber
{
get { return _args.Number; }
}
public string ErrorMessage
{
get { return _args.Message; }
}
public int? ErrorLogId
{
get { return _args.ErrorLogId; }
}
public int? SqlErrorNumber
{
get { return _args.SqlErrorNumber; }
}
public string SqlErrorMessage
{
get { return _args.SqlErrorMessage; }
}
}
Now here is where it all comes together... Using the example that I started with in my initial inquiry, here is what the 'AddCategory()' method might look like:
public void AddCategory(Category category)
{
var args = new MySprocArgs("AddCategory");
var result = _dbContext.AddWidgetSproc(
category.CreatedByUserId,
category.Name,
category.IsActive,
ref args.Number, // <-- Notice use of 'args'
ref args.Message,
ref args.ErrorLogId,
ref args.SqlErrorNumber,
ref args.SqlErrorMessage,
ref args.NewRowId);
if (result == -1)
throw new MySprocException(args);
}
Now from my controller, I simply do the following:
[HandleError(ExceptionType = typeof(MySprocException), View = "SprocError")]
public class MyController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Category category)
{
if (!ModelState.IsValid)
{
// manage friendly messages
return View(category);
}
_repository.AddCategory(category);
return RedirectToAction("Index");
}
}
The trick to managing the new MySprocException is to simply trap it using the HandleError attribute and redirect the user to a page that understands the MySprocException.
I hope this helps somebody. :)
I don't believe you can add the output parameters to any of your LINQ classes because the parameters do not persist in any table in your database.
But you can handle output parameters in LINQ in the following way.
Add the stored procedure(s) you whish to call to your .dbml using the designer.
Call your stored procedure in your code
using (YourDataContext context = new YourDataContext())
{
Nullable<int> errNumber = null;
String errMessage = null;
Nullable<int> errDetailLogID = null;
Nullable<int> sqlErrNumber = null;
String sqlErrMessage = null;
Nullable<int> newRowID = null;
Nullable<int> userID = 23;
Nullable<bool> isActive=true;
context.YourAddStoredProcedure(userID, "New Category", isActive, ref errNumber, ref errMessage, ref errDetailLogID, ref sqlErrNumber, ref sqlErrMessage, ref newRowID);
}
I haven' tried it yet, but you can look at this article, where he talks about stored procedures that return output parameters.
http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx
Basically drag the stored procedure into your LINQ to SQL designer then it should do the work for you.
The dbContext.SubmitChanges(); will work only for ENTITY FRAMEWORK.I suggest Save,Update and delete will work by using a Single Stored procedure or using 3 different procedure.

Resources