ASP.NET - How to set optional field in ViewModel class? - asp.net

Working on ASP.NET project, I am now facing a problem.
Frontend Data
fruits = [
{
type: "First",
size: 50,
weight: 120,
optionalParam1: "String",
optionalParam2: 152
},
{
type: "Second",
size: 12,
weight: 160,
optionalParam3: "Another String",
optionalParam4: 169
},
{
type: "Third",
size: 15,
weight: 190,
optionalParam1: "String for Third",
optionalParam5: [1, 2]
}
]
saleInfo = {
param1: 12,
param2: "string",
param3: 150
}
ViewModel Class
public class FruitViewModel {
public Dictionary<string, dynamic>[] fruits;
public Dictionary<string, dynamic> saleInfo;
public int total;
public Dictionary<string, dynamic> prevInfo;
}
Just want to store this information to the sql server and restore them from the sql db. But I am not sure if it's correct to use Dictionary for this.
Would you guide me how to receive this information and save to the sql db?
Also how to restore this information from the sql db and send to the frontend?
PS. Here the prevInfo parameter is the same as the saleInfo parameter, but as the name means, it's optional. It's null for request, only available for the response.

A list works fine.
For the first one create a class which mirrors what your front-end expects, something like:
public class FruitModel {
public string type { get; set; },
public int size { get;set; },
//the rest of properties you want
}
then your ViewModel starts to look like this:
public class FruitViewModel {
public List<FruitModel> fruits;
//change the rest to match
public Dictionary<string, dynamic> saleInfo;
public int total;
public Dictionary<string, dynamic> prevInfo;
}
the List will be serialised to Array on the front-end. You will need to do some manipulation as well since your data will be encapsulated into a holder object.
if you get the data in a variable called apiData then you will access the rest with apiData.fruits and the first item is apiData.fruits[0] for example.
if you want to make your life easy on the front-end, all you have to do is assign the response data straight to your variables, something like:
fruits = apiData.fruits;
nothing else needs to change then.

In VB, when using EF, you can make certain types of property optional by adding ? to the end of the field definition in your Model (i.e. make it nullable). Strings don't need this.
e.g.
Public Property optionalparam1 As String
Public Property optionalparam2 As Integer?
Public Property optionalparam3 As String
Public Property optionalparam4 As Integer?
Re. optional parameter 5, not sure about arrays and object elements, I am looking into that myself now. Good luck ;)
UPDATE: arrays are like Strings, they are references and so always nullable, so special treatment required.

Related

Convention based Entity Framework Core returning the object associated with the foreign key when using Web API

I'm using EF code first. By convention, I have added a foreign key and a reference to the foreign object (I believe this is needed). When I send a Get request to the API, it returns an IEnumerable. The problem is that each record returned also returns the complete object for the foreign key.
I've tried Googling the answer and for questions here on SO. I tried commenting out the reference to the other object but that didn't work.
public class Bill
{
// other properties
public Guid PersonId { get; set; } // this is the foreign key
public Person Person { get; set; } // this is the reference to the foreign object
}
This is what is returned when executing the Get request:
[
{
//other fields
"personId": "c28e52b0-1e40-46c4-812b-a61be7a69d53",
"person": {
//the entire other person object is returned here
}
},
]
How do I solve this without establishing a DTO for every model?
I'd like to hear if I'm using code first conventions improperly.
ASP.NET core 2.2 doesn't have return type Json(Object) as 2.1 did.
An ActionResult returning an anonymous type is one option, if you didn't want to use a DTO.
public IActionResult Get()
{
return new OkObjectResult(new { PersonId = 99, OtherProperty = "more stuff" });
}
Response body:
{
"personId": 99,
"otherProperty": "more stuff"
}
Use ObjectResult if you need to return various status codes:
return new ObjectResult(new { PersonId = 99, OtherProperty = "more stuff"}) {StatusCode = 200};

Why is my abstract JSON object not being parsed?

I just spent a long time trying to work this one out, so I'm posting here in case anyone else makes the same mistake as me.
So, to replicate the situation, I just had a few classes with basic inheritance:
public abstract class Foo
{
public string Name { get; set; }
}
public class Bar : Foo
{
public int SomethingSpecial { get; set; }
}
public class Baz : Foo
{
public string SomethingMundane { get; set; }
}
Now, I want to be able to take a json string, and parse back a concrete implementation of Foo, without knowing beforehand which type the json represents. JSON.Net handles this, by using a $type variable to look up the type of the object:
{
"$type": "MyNamespace.Bar",
"Name": "Resources",
"SomethingSpecial": 42
}
When deserializing the object, you may want to specify the type handling options, and a custom binder, in the JsonSerializerSettings, but that's optional.
The problem I ran into was that when posting the json from a web client, the object was not being deserialized, instead either throwing an exception, or in the case of a POST parameter in ASP.Net, the value was just coming in as null.
The problem here is that Newtonsoft.Json (at least, the version I'm using - 9.0.1) expects the $type element to be the first element of the object, and will ignore it when it is in any other position. So the following json, while technically equivalent to the json in the question, will not work:
{
"Name": "Resources",
"$type": "MyNamespace.Bar",
"SomethingSpecial": 42
}
There is a setting for this, although it may have a performance impact:
new JsonSerializerSettings
{
// $type no longer needs to be first
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
}
It's worth noting that if you're using JavaScript's JSON.stringify function, properties are generally written out in the order they were first assigned to the object, so you could also make sure the first thing you do is assign $type.

How do I get the strongly-typed value of an OutArgument in code?

Given an Activity (created via the designer) that has several OutArgument properties, is it possible to get their strongly-typed value from a property after invoking the workflow?
The code looks like this:
// generated class
public partial class ActivityFoo : System.Activities.Activity....
{
....
public System.Activities.OutArgument<decimal> Bar { ... }
public System.Activities.OutArgument<string> Baz { ... }
}
// my class
var activity = new ActivityFoo();
var result = WorkflowInvoker.Invoke(activity);
decimal d = activity.Bar.Get(?)
string s = activity.Baz.Get(?)
The T Get() method on OutArgument<T> that requires an ActivityContext which I'm not sure how to obtain in code.
I also realize it's possible to get the un-typed values from result["Bar"] and result["Baz"] and cast them, but I'm hoping there's another way.
Updated to make it clear there are multiple Out values, although the question would still apply even if there was only one.
If you look at workflows as code, an Activity is no more than a method that receives input arguments and (potentially) returns output arguments.
It happens that Activities allows one to return multiple output arguments, something that C# methods, for example, don't (actually that's about to change with C# 7 and tuples).
That's why you've an WorkflowInvoker.Invoke() overload which returns a Dictionary<string, object> because the framework obviously doesn't know what\how many\of what type output arguments you have.
Bottom line, the only way for you to do it fully strong-typed is exactly the same way you would be doing on a normal C# method - return one OutArgument of a custom type:
public class ActivityFooOutput
{
public decimal Bar { get; set }
public decimal Baz { get; set; }
}
// generated class
public partial class ActivityFoo : System.Activities.Activity....
{
public System.Activities.OutArgument<ActivityFooOutput> Result { ... }
}
// everything's strongly-typed from here on
var result = WorkflowInvoker.Invoke<ActivityFooOutput>(activity);
decimal d = result.Bar;
string s result.Baz;
Actually, if you don't want to create a custom type for it, you can use said tuples:
// generated
public System.Activities.OutArgument<Tuple<decimal, string>> Result { ... }
// everything's strongly-typed from here on
var result = WorkflowInvoker.Invoke<Tuple<decimal, string>>(activity);
decimal d = result.Item1;
string s result.Item2;
Being the first option obviously more scalable and verbose.

Is there a way to customize the ObjectMapper used by Spring MVC without returning String?

I have a graph of objects that I'd like to return different views of. I don't want to use Jackson's #JsonViews to implement this. Right now, I use Jackson MixIn classes to configure which fields are shown. However, all my rest methods return a String rather than a type like BusinessCategory or Collection< BusinessCategory >. I can't figure out a way to dynamically configure the Jackson serializer based on what view I'd like of the data. Is there any feature built into Spring to configure which Jackson serializer to use on a per-function basis? I've found posts mentioning storing which fields you want in serialized in thread-local and having a filter send them and another post filtering based on Spring #Role, but nothing addressing choosing a serializer (or MixIn) on a per-function basis. Any ideas?
The key to me thinking a proposed solution is good is if the return type is an object, not String.
Here are the objects in my graph.
public class BusinessCategory implements Comparable<BusinessCategory> {
private String name;
private Set<BusinessCategory> parentCategories = new TreeSet<>();
private Set<BusinessCategory> childCategories = new TreeSet<>();
// getters, setters, compareTo, et cetera
}
I am sending these across the wire from a Spring MVC controller as JSON like so:
#RestController
#RequestMapping("/business")
public class BusinessMVC {
private Jackson2ObjectMapperBuilder mapperBuilder;
private ObjectMapper parentOnlyMapper;
#Autowired
public BusinessMVCfinal(Jackson2ObjectMapperBuilder mapperBuilder) {
this.mapperBuilder = mapperBuilder;
this.parentOnlyMapper = mapperBuilder.build();
parentOnlyMapper.registerModule(new BusinessCategoryParentsOnlyMapperModule());
}
#RequestMapping(value="/business_category/parents/{categoryName}")
#ResponseBody
public String getParentCategories(#PathVariable String categoryName) throws JsonProcessingException {
return parentOnlyMapper.writeValueAsString(
BusinessCategory.businessCategoryForName(categoryName));
}
}
I have configure the serialization in a MixIn which is in turn added to the ObjectMapper using a module.
public interface BusinessCategoryParentsOnlyMixIn {
#JsonProperty("name") String getName();
#JsonProperty("parentCategories") Set<BusinessCategory> getParentCategories();
#JsonIgnore Set<BusinessCategory> getChildCategories();
}
public class BusinessCategoryParentsOnlyMapperModule extends SimpleModule {
public BusinessCategoryParentsOnlyMapperModule() {
super("BusinessCategoryParentsOnlyMapperModule",
new Version(1, 0, 0, "SNAPSHOT", "", ""));
}
public void setupModule(SetupContext context) {
context.setMixInAnnotations(
BusinessCategory.class,
BusinessCategoryParentsOnlyMixIn.class);
}
}
My current solution works, it just doesn't feel very clean.
"categories" : [ {
"name" : "Personal Driver",
"parentCategories" : [ {
"name" : "Transportation",
"parentCategories" : [ ]
} ]
}
Oh yes, I'm using:
spring-boot 1.2.7
spring-framework: 4.1.8
jackson 2.6.3
Others listed here: http://docs.spring.io/spring-boot/docs/1.2.7.RELEASE/reference/html/appendix-dependency-versions.html
In the end, the only process that met my needs was to create a set of view objects which exposed only the fields I wanted to expose. In the grand scheme of things, it only added a small amount of seemingly unnecessary code to the project and made the flow of data easier to understand.

ASP.NET MVC - Posting a form with custom fields of different data types

In my ASP.NET MVC 2 web application, I allow users to create custom input fields of different data types to extend our basic input form. While tricky, building the input form from a collection of custom fields is straight-forward enough.
However, I'm now to the point where I want to handle the posting of this form and I'm not certain what the best way to handle this would be. Normally, we'd use strongly-typed input models that get bound from the various statically-typed inputs available on the form. However, I'm at a loss for how to do this with a variable number of input fields that represent different data types.
A representative input form might look something like:
My date field: [ date time input
control ]
My text field: [ text input
field ]
My file field: [ file upload
control ]
My number field: [ numerical input control ]
My text field 2: [text input field ]
etc...
Ideas I've thought about are:
Sending everything as strings (except for the file inputs, which would need to be handled specially).
Using a model with an "object" property and attempting to bind to that (if this is even possible).
Sending a json request to my controller with the data encoded properly and attempting to parse that.
Manually processing the form collection in my controller post action - certainly an option, but I'd love to avoid this.
Has anyone tackled an issue like this before? If so, how did you solve it?
Update:
My "base" form is handled on another input area all together, so a solution doesn't need to account for any sort of inheritence magic for this. I'm just interested in handling the custom fields on this interface, not my "base" ones.
Update 2:
Thank you to ARM and smartcaveman; both of you provided good guidance for how this could be done. I will update this question with my final solution once its been implemented.
This is how I would begin to approach the issue. A custom model binder would be pretty easy to build based on the FormKey property (which could be determined by the index and/or label, depending).
public class CustomFormModel
{
public string FormId { get; set; }
public string Label { get; set; }
public CustomFieldModel[] Fields { get; set; }
}
public class CustomFieldModel
{
public DataType DateType { get; set; } // System.ComponentModel.DataAnnotations
public string FormKey { get; set; }
public string Label { get; set; }
public object Value { get; set; }
}
public class CustomFieldModel<T> : CustomFieldModel
{
public new T Value { get; set; }
}
Also, I noticed one of the comments below had a filtered model binder system. Jimmy Bogard from Automapper made a really helpful post about this method at http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/03/17/a-better-model-binder.aspx , and later revised in, http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/11/19/a-better-model-binder-addendum.aspx . It has been very helpful for me in building custom model binders.
Update
I realized that I misinterpreted the question, and that he was specifically asking how to handle posting of the form "with a variable number of input fields that represent different data types". I think the best way to do this is to use a structure similar to above but leverage the Composite Pattern. Basically, you will need to create an interface like IFormComponent and implement it for each datatype that would be represented. I wrote and commented an example interface to help explain how this would be accomplished:
public interface IFormComponent
{
// the id on the html form field. In the case of a composite Id, that doesn't have a corresponding
// field you should still use something consistent, since it will be helpful for model binding
// (For example, a CompositeDateField appearing as the third field in the form should have an id
// something like "frmId_3_date" and its child fields would be "frmId_3_date_day", "frmId_3_date_month",
// and "frmId_3_date_year".
string FieldId { get; }
// the human readable field label
string Label { get; }
// some functionality may require knowledge of the
// Parent component. For example, a DayField with a value of "30"
// would need to ask its Parent, a CompositeDateField
// for its MonthField's value in order to validate
// that the month is not "February"
IFormComponent Parent { get; }
// Gets any child components or null if the
// component is a leaf component (has no children).
IList<IFormComponent> GetChildren();
// For leaf components, this method should accept the AttemptedValue from the value provider
// during Model Binding, and create the appropriate value.
// For composites, the input should be delimited in someway, and this method should parse the
// string to create the child components.
void BindTo(string value);
// This method should parse the Children or Underlying value to the
// default used by your business models. (e.g. a CompositeDateField would
// return a DateTime. You can get type safety by creating a FormComponent<TValue>
// which would help to avoid issues in binding.
object GetValue();
// This method would render the field to the http response stream.
// This makes it easy to render the forms simply by looping through
// the array. Implementations could extend this for using an injected
// formatting
void Render(TextWriter writer);
}
I am assuming that the custom forms can be accessed via some sort of id which can be contained as a form parameter. With that assumption, the model binder and provider could look something like this.
public interface IForm : IFormComponent
{
Guid FormId { get; }
void Add(IFormComponent component);
}
public interface IFormRepository
{
IForm GetForm(Guid id);
}
public class CustomFormModelBinder : IModelBinder
{
private readonly IFormRepository _repository;
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult result;
if(bindingContext.ValueProvider.TryGetValue("_customFormId", out result))
{
var form = _repository.GetForm(new Guid(result.AttemptedValue));
var fields = form.GetChildren();
// loop through the fields and bind their values
return form;
}
throw new Exception("Form ID not found.");
}
}
Obviously, all the code here is just to get the point across, and would need to be completed and cleaned up for actual use. Also, even if completed this would only bind to an implementation of the IForm interface, not a strongly typed business object. (It wouldn't be a huge step to convert it to a dictionary and build a strongly typed proxy using the Castle DictionaryAdapter, but since your users are dynamically creating the forms on the site, there is probably no strongly typed model in your solution and this is irrelevant). Hope this helps more.
Take a peek at what I did here: MVC2 Action to handle multiple models and see if can get you on the right track.
If you use a FormCollection as one of your parameters to your action, you can then go thru that form collection looking for bits of data here or there in order to bind those values to whatever an then save the data. You are most likely going to need to take advantage of both strategy and command patterns to get this to work.
Best of luck, feel free to ask follow-up questions.
Edit:
Your method which does the work should look something like this:
private/public void SaveCustomFields(var formId, FormCollection collection) //var as I don't know what type you are using to Id the form.
{
var binders = this.binders.select(b => b.CanHandle(collection)); //I used IOC to get my list of IBinder objects
// Method 1:
binders.ForEach(b => b.Save(formId, collection)); //This is the execution implementation.
// Method 2:
var commands = binders.Select(b => b.Command(formId, collection));
commands.ForEach(c => c.Execute());
}
public DateBinder : IBinder //Example binder
{
public bool CanHandle(FormCollection collection)
{
return (null != collection["MyDateField"]); //Whatever the name of this field is.
}
//Method 1
public void Save(var formId, FormCollection collection)
{
var value = DateTime.Parse(collection["MyDateField"]);
this.someLogic.Save(formId, value); //Save the value with the formId, or however you wish to save it.
}
//Method 2
public Command Command(var formId, FormCollection collection)
{
//I haven't done command pattern before so I'm not sure exactly what to do here.
//Sorry that I can't help further than that.
}
}
I would think one of the best options is to create a custom model binder, which makes it possible to have custom logic behind the scenes and still very customizable code behind.
Maybe these articles can help you:
http://www.gregshackles.com/2010/03/templated-helpers-and-custom-model-binders-in-asp-net-mvc-2/
http://www.singingeels.com/Articles/Model_Binders_in_ASPNET_MVC.aspx
More specifically I would probably take as the controller argument a custom class with all "base" properties included. The class could then for example include a dictionary linking the name of each field to either just an object or an interface which you implement once for each data-type making it simple to process the data later.
/Victor

Resources