Is a kind of TypeDescriptor or RouteValueDictionary available in portable class library? - portable-class-library

I'm searching for a way to pass an argument which value is a dictionary constructed from an object: MyMethod(new { param1="public", param2=123 }).
Using RouteValueDictionary we can easily convert the object into an IDictionary. But RouteValueDictionary requires TypeDescriptor which is not available in PCL.
Is there an another way to do it ?
==== EDIT ====
Found a working code for profile 104:
void MyMethod(object oParams)
{
var dic = from property in oParams.GetType().GetProperties()
select new KeyValuePair<string,object>(property.Name, property.GetValue(oParams,null));
...
}

Related

get original entity from EntityStream

I'm using Jax RS 2.0 ContainerRequestFilter
I want to intercept entity body (if any) and convert to original type.
I can get original class type by using inkected ResourceInfo
resinfo.getResourceMethod().getParameters()
However I have no idea on how to get parameter value...
The only closes object is an EntityStream(), available from:
containerRequestContext.getEntityStream()
I guess I should use the above object, but how I can rebuild original object from entityStream ?
I found a way, it is enought to implement ReaderInterceptor interface:
#Override
public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext) throws IOException, WebApplicationException {
final Object proceed = readerInterceptorContext.proceed();
return proceed;
}

String Trim Model Binder in ASP .NET Core 2

I'm working on a .NET Core 2 API project and have been trying to implement a universal string trim model binder that would trim all string values of provided request parameters and field values. So far I have had mixed results and am struggling to find working example that would point me in the right direction. I've been trying to implement the same model binder as posted by Vikash Kumar.
This model binder works fine for all string values that are passed into controller actions via direct parameters, such as public IActionResult Profile(string username), but for string fields in complex objects the BindModelAsync method of the TrimmingModelBinder class never gets called. An example of an HttpPost action in my controller would be public IActionResult Profile([FormBody] ProfileLookupModel model). The model binder does not seem to check the fields of the complex model. It also doesn't work for fields that are Lists of strings.
I recall prior to .NET Core, specifying a string trim model binder would recursively check each field of complex models, even models within complex models. This doesn't seem to be the case in .NET Core, but I might be wrong. My project is targeting the netcoreapp2.0 framework.
I'm curious if anyone has had the same issue as me and possibly found a solution for it.
Note: I haven't posted any sample code as it is the same as the code from the referenced article.
I'll add my 2 cents here. Instead of using some kind of model binding hook, I went to a action filter. One of the advantages is that the developer can select which actions to use, instead of having this processing for all requests and model bindings (not that it should affect performance that much). Btw action filters can also be applied globally.
Here is my code, first create an action filter.
public class TrimInputStringsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
foreach (var arg in context.ActionArguments.ToList())
{
if (arg.Value is string)
{
if (arg.Value == null)
{
continue;
}
string val = arg.Value as string;
if (!string.IsNullOrEmpty(val))
{
context.ActionArguments[arg.Key] = val.Trim();
}
continue;
}
Type argType = arg.Value.GetType();
if (!argType.IsClass)
{
continue;
}
TrimAllStringsInObject(arg.Value, argType);
}
}
private void TrimAllStringsInObject(object arg, Type argType)
{
var stringProperties = argType.GetProperties()
.Where(p => p.PropertyType == typeof(string));
foreach (var stringProperty in stringProperties)
{
string currentValue = stringProperty.GetValue(arg, null) as string;
if (!string.IsNullOrEmpty(currentValue))
{
stringProperty.SetValue(arg, currentValue.Trim(), null);
}
}
}
}
To use it, either register as global filter or decorate your actions with the TrimInputStrings attribute.
[TrimInputStrings]
public IActionResult Register(RegisterViewModel registerModel)
{
// Some business logic...
return Ok();
}
TrimmingModelBinder is essentially configured for strings only, and defaults back to SimpleTypeModelBinder if it fails, or other binders configured. So if your implementation is essentially the same as in TrimmingModelBinder then it will definitely work for strings only.
For complex types, I recommend creating a new binder, and its corresponding provider, which will have to check all string properties in the model type and trim the value before binding. Then register this binder at index 0 such that its the first one checked before any other binders are tried.
services.AddMvc(options => option.ModelBinderProviders.Insert(0, new MyComplexTypeModelBinderProvider());

ASP.NET Web API - ModelBinders

I need to use a custom modelbinder of some kind to always treat incoming dates in UK format, i have setup a custom model binder and registered like so:
GlobalConfiguration.Configuration.BindParameter(typeof(DateTime), new DateTimeModelBinder());
This only seems to work for querystring parameters, and only works if i specify [ModelBinder] on my parameter like so, is there i way to make all actions use my model binder:
public IList<LeadsLeadRowViewModel> Get([ModelBinder]LeadsIndexViewModel inputModel)
Also, how can i get my posted form to my Api controller to use my model binder?
You can register a model binder globally by implementing a ModelBinderProvider and inserting it into the list of services.
Example use in Global.asax:
GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, new Core.Api.ModelBinders.DateTimeModelBinderProvider());
Below is example code demonstrating a ModelBinderProvider and a ModelProvider implemenation that converts DateTime arguments in a culture aware manner (using the current threads culture);
DateTimeModelBinderProvider implementation:
using System;
using System.Web.Http;
using System.Web.Http.ModelBinding;
...
public class DateTimeModelBinderProvider : ModelBinderProvider
{
readonly DateTimeModelBinder binder = new DateTimeModelBinder();
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
if (DateTimeModelBinder.CanBindType(modelType))
{
return binder;
}
return null;
}
}
DateTimeModelBinder implementation:
public class DateTimeModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
ValidateBindingContext(bindingContext);
if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName) ||
!CanBindType(bindingContext.ModelType))
{
return false;
}
bindingContext.Model = bindingContext.ValueProvider
.GetValue(bindingContext.ModelName)
.ConvertTo(bindingContext.ModelType, Thread.CurrentThread.CurrentCulture);
bindingContext.ValidationNode.ValidateAllProperties = true;
return true;
}
private static void ValidateBindingContext(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException("bindingContext");
}
if (bindingContext.ModelMetadata == null)
{
throw new ArgumentException("ModelMetadata cannot be null", "bindingContext");
}
}
public static bool CanBindType(Type modelType)
{
return modelType == typeof(DateTime) || modelType == typeof(DateTime?);
}
}
I think you don't need a model binder. Your approach is incorrect. The right approach for dates is using a client side globalization library like the globalize library to parse dates formatted in any language and transform them into JavaScript date objects. Then you can serialize your datascript data structures in JSON with the browser JSON.stringify, and this should work.
It is better to use always standard formats for dates and to use a formatter instead than a model binder. Available formatters handle also TimeZones correctly, if you use the kind parameter of your C# DateTime objects to specify if the date time is expressed in local time or in UTC time.
Attribute routing seems to conflict with model binding. If you use attribute routing, you can wrap the global.asax configuration into a single GlobalConfiguration.Config call to avoid the initialisation issues:
GlobalConfiguration.Configure(config =>
{
config.BindParameter(typeof(DateTime), new DateTimeModelBinder());
config.MapHttpAttributeRoutes();
}
(This might be fixed in the upcoming ASP.NET 5 if it's related to bug #1165.)
You do not need a custom model binder for that. You should be good by changing the thread culture to UK or set your web.config settings for UK, if this is what your site is using all the time.
If not, you can still change the DateTimeFormatInfo for the CurrentCulture to UK one.
There is also a good post about model binders available here by Scott Hanselman.
You can put this in Global.asax:
ModelBinders.Binders[typeof(DateTime)] = new DateAndTimeModelBinder()

PexChoose non generic methods

Is there any way to specify the return type for PexChoose at runtime? For example PexChoose.Value(name, Type)?
This would be useful to make general models that generate values of different types depending on runtime contraints.
You could build your own helper class which will call the generic version via reflection.
For instance, to create a non-generic version of PexChoose.Value(string name)
public static class MyPexChoose
{
public static object Value(Type myType, string name)
{
// Find the PexChoose.Value() method which has a single string parameter
MethodInfo method = typeof(PexChoose).GetMethod("Value", new Type[1] {typeof(string)});
// Make and invoke the generic version of it
MethodInfo generic = method.MakeGenericMethod(myType);
return generic.Invoke(typeof(PexChoose), new object[1] { name });
}
}
Then the call
MyPexChoose(typeof(DateTime), "MyChosen");
is equivalent to
PexChoose<DateTime>("MyChosen");

Handling a C# method that isn't defined on a dynamic object (aka respond_to/method_missing)

Given the new dynamic support in C# 4, is it possible to write a class in such a way that if a method is invoked on an instance and that method is not present, dispatch is passed to another method? This might look something like:
public class Apple : ... {
// ...
private ... MethodMissing(string name, ...) {
if (name == "TurnIntoOrange") {
// do something
}
}
}
dynamic d = new Apple();
d.TurnIntoOrange(); // Not actually defined on Apple; will pass to MethodMissing.
Other languages would call this "method_missing support", under the more general heading of metaprogramming. I'm not sure what C# calls this specifically. But is it possible?
Absolutely. Either implement IDynamicMetaObjectProvider or derive from DynamicObject for a much simpler route. See the DLR documentation for some good examples.
Here's a quick example of DynamicObject:
using System;
using System.Dynamic;
public class MyDynamic : DynamicObject
{
public override bool TryInvokeMember
(InvokeMemberBinder binder,
object[] args,
out object result)
{
Console.WriteLine("I would have invoked: {0}",
binder.Name);
result = "dummy";
return true;
}
public string NormalMethod()
{
Console.WriteLine("In NormalMethod");
return "normal";
}
}
class Test
{
static void Main()
{
dynamic d = new MyDynamic();
Console.WriteLine(d.HelloWorld());
Console.WriteLine(d.NormalMethod());
}
}
<plug>
I have a bigger example of DynamicObject in the 2nd edition of C# in Depth but I haven't yet implemented IDyamicMetaObjectProvider. I'll do so before the book's release, but the early access edition only has the DynamicObject example at the moment. Btw, if you buy it today it's half price - use the code twtr0711. I'll edit this answer later on to remove that bit :)
</plug>