I have a WebApi method, like this one:
public string Get([FromUri] SampleInput input)
{
//do stuff with the input...
return "ok";
}
The input is defined like this:
public class SampleInput
{
// ...other fields
public bool IsAwesome { get; set; }
}
As it is, it works OK: if I pass &isAwesome=true in the query string, the parameter is initializes with the value true.
My problem is that I'd like to accept both &isAwesome=true and &isAwesome=1 as true values. Currently, the second version will result in IsAwesome being false in the input model.
What I tried, after reading the various blog posts on the subject, was to define an HttpParameterBinding:
public class BooleanNumericParameterBinding : HttpParameterBinding
{
private static readonly HashSet<string> TrueValues =
new HashSet<string>(new[] { "true", "1" }, StringComparer.InvariantCultureIgnoreCase);
public BooleanNumericParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor)
{
}
public override Task ExecuteBindingAsync(
ModelMetadataProvider metadataProvider,
HttpActionContext actionContext,
CancellationToken cancellationToken)
{
var routeValues = actionContext.ControllerContext.RouteData.Values;
var value = (routeValues[Descriptor.ParameterName] ?? 0).ToString();
return Task.FromResult(TrueValues.Contains(value));
}
}
... and register it in Global.asax.cs, using:
var pb = GlobalConfiguration.Configuration.ParameterBindingRules;
pb.Add(typeof(bool), p => new BooleanNumericParameterBinding(p));
and
var pb = GlobalConfiguration.Configuration.ParameterBindingRules;
pb.Insert(0, typeof(bool), p => new BooleanNumericParameterBinding(p));
None of these worked. My custom HttpParameterBinding is not being called and I still get the value 1 translated to false.
How can I configure WebAPI to accept the value 1 as true for Booleans?
Edit: The example I presented is intentionally simplified. I have a lot of input models in my application and they contain many boolean fields that I would like to be handled in the manner described above. If there was just this one field, I would not have resorted to such complex mechanisms.
Looks like decorating the parameter with the FromUriAttribute just skips the parameter binding rules altogether. I made a simple test replacing the SampleInput input parameter with a simple bool:
public string Get([FromUri] bool IsAwesome)
{
//do stuff with the input...
return "ok";
}
and the boolean rule is still not getting called (IsAwesome is coming as null when you call &isAwesome=1).
As soon as you remove the FromUri attribute:
public string Get(bool IsAwesome)
{
//do stuff with the input...
return "ok";
}
the rule gets called and the parameter correctly bound.
The FromUriAttribute class is sealed, so I think you're pretty much screwed - well, you can always reimplement it and include your alternate boolean binding logic ^_^.
Related
When logging data, I want a generic reference to the containing class. That way, if the code is moved elsewhere, the class name will change accordingly. (Otherwise, if the code moves to nameof(Class2), it will still be logged incorrectly as nameof(Class1)). For example:
class Class_Name {
ICommand Command_Name =>
new RelayCommand(() =>
{
// An loggable event occurs
// Is there a smart and uncomplicated way of doing this generically?
var provenance = $"{nameof(Class_Name)}.{nameof(Command_Name)}";
// The event of whatever kind gets logged
});
}
// OR
void Method_Name() {
var provenance = $"{nameof(Class_Name)}.{nameof(Method_Name)}";
}
}
Using a generic nameof(this), where this should refer to the class itself, causes a compilation error: CS8081: Expression does not have a name. Using this.GetType() causes the same problem.
Not really understanding why the this keyword does not refer to the containing class in this context. Is there a way to refer to the current class generically?
If you combine the suggestion in the comments (this.GetType().Name) with a [CallerMemberName] attribute via a helper method, you can accomplish what you're looking for in a reusable fashion.
public class Class_Name
{
public void Method_Name()
{
var provenance = CreateProvenance();
Console.WriteLine(provenance);
}
private string CreateProvenance([CallerMemberName] string methodName = "")
{
return $"{this.GetType().Name}.{methodName}";
}
}
This outputs "Class_Name.Method_Name".
You can even turn this into a handy extension method that allows you to call it from any method.
public class Class_Name
{
public void Method_Name()
{
var provenance = this.CreateProvenance();
Console.WriteLine(provenance);
}
}
public static class ProvenanceExtensions
{
public static string CreateProvenance(this object context,
[CallerMemberName] string methodName = "")
{
return $"{context.GetType().Name}.{methodName}";
}
}
As Jeppe Stig Nielsen pointed out, you may not want the inheriting runtime type to be used, which is what context.GetType().Name will return. If you want to get the compile-time type instead, you can use generics.
public static class ProvenanceExtensions
{
public static string CreateProvenance<T>(this T context,
[CallerMemberName] string methodName = "")
{
return $"{typeof(T).Name}.{methodName}";
}
}
By design:
A nameof expression is evaluated at compile time and has no effect at
run time.
To access the type dynamically, in the runtime, you may use the GetType method. Just rememeber not to combine it with the nameof.
class Class_Name {
void Method_Name() {
// An event occurs
// Is there a smart and uncomplicated way of doing this generically?
var provenance = $"{this.GetType().Name}.{MethodBase.GetCurrentMethod().Name}";
// The event of whatever kind gets logged
}
}
Is there a way to make a function use its optional parameter's value? For example, say I have,
public void myFunction(bool required, string optional = "This is optional") {...}
and I want to do something like this,
string possiblyNull = null; // the result of another function
myFunction(true, possiblyNull ?? possiblyNull : optional)
C# compiler embeds the parameter’s default value whenever arguments are left out at the call site. And in your case your want to call your method with that parameter. So, it is not possible, so you have to use that check either outside or inside of your method. If you really want to prevent using if clause while calling your mehtod, then you can change signature of your method so:
public void myFunction(bool required, string optional)
{
optional = optional ?? "This is optional";
...
}
And then call it so:
string possiblyNull = null; // the result of another function
myFunction(true, possiblyNull)
You can't get the default value at the call site. You'd need to have a check outside the method call.
string possiblyNull = null;
// ...
if (possiblyNull == null)
myFunction(true);
else
myFunction(true, possiblyNull);
If your concern is that
You don't want to just make null the default because that would mean the default wouldn't appear in Intellisense and the caller wouldn't see the default
You could make some value the default and then check for null, and if it's null replace it with the default, but that would mean putting the default in two places
You could do this:
private const string OptionalValue = "This is optional!";
public void myFunction(bool required, string optional = OptionalValue)
{
optional = optional ?? OptionalValue;
}
Now you get both. The default shows up in Intellisense and it's not repeated.
If it's just that you
might need to pass a null value
want to get the default value
have to do so frequently enough that it's annoying
can't modify the original method
you could create an extension for the class containing the method:
public static class Extension
{
// I can't think of how this function name would not be awkward.
public static void MyFunctionThatReplacesNullWithDefault(
this ClassWithOptionalMethod target, bool required, string optional = null)
{
if(optional == null)
target.myFunction(required);
else
target.myFunction(required, optional);
}
}
you are quite there but you only need to remove possiblyNull: while you passing the parameter to the method,
you can do like this...
public partial class MainWindow : Window
{
private string optional = "Test";
string possiblyNull = null;
public MainWindow()
{
InitializeComponent();
// here you can check null
myFunction(true, possiblyNull ?? optional);
// Or
myFunction(true);
}
public void myFunction(bool required, string optional = "This is optional")
{
MessageBox.Show(optional);
}
}
I have a property with has an attribute, which in turn has Func<object, object>, I want that function to be executed (using the updated property's value as in T) upon the property change. What's the slickest way of doing so?
Note: I'm aware of the facts that Attributes are static and aren't designed to be executed upon their assignees change/invocaction. I just need to get it working as close as can to the prototype I've created.
Some code:
using System;
using System.Windows;
namespace AnnotatedBinding
{
public class AnnotatedPropertyAttribute: Attribute
{
// static
public AnnotatedPropertyAttribute(Func<object, object> evaluator)
{
Evaluator = evaluator;
}
public Func<object, object> Evaluator
{
get; private set;
}
}
public class Test
{
[AnnotatedProperty(Test.TestEvaluator)] // not compiling!, guess it's fixable by passing in a member info and then calling Reflection Invoke?
public string TestProperty
{
get; set;
}
public static Func<object, object> TestEvaluator = (x) => MessageBox.Show(x.ToString());
}
public class Shell
{
public void Run()
{
var test = new Test();
test.TestProperty = "blah";// I want my message box here
test.TestProperty = "blah";// and I don't want it here
}
}
}
Your attribute on the TestProperty does not compile because delegates are not allowed as attribute arguments. See this answer from Eric Lippert for details about which types are allowed.
Regarding a workaround using reflection: You could certainly specify the type owning the method, and the name of the method in the attribute since System.Type and string are valid attribute argument types. Something like this:
[AnnotatedProperty(typeof(Test), "TestEvaluator")]
public string TestProperty { get; set; }
However, this still won't do anything with the delegate when the property is set. Attributes are only metadata that you can read out during runtime using reflection (more specifically using MemberInfo.GetCustomAttributes(...)), analyse them and perform any operation based on the attribute values. This all needs to be done manually. Unfortunately, the .NET framework does not offer the functionality to automatically perform some operation based on the attributes that are applied to a member. This would make life a lot easier for property change notifications as well.
So you would have to implement the handling of the attributes manually. That means, implementing the get and set accessors, checking whether the attribute is applied to that property, determine the delegate that should be executed, and exeute it using reflection. Of course, that does not make sense because you would rather add a call to the method in the setter instead.
tl;dr:
Possible solution: You should have a look at PostSharp, a library supporting aspect-oriented programming in .NET. It can be used to inject boiler-plate code into methods or other members after compilation. It does this by analyzing your MSIL code and searching for so-called "aspects" (which are actually attributes, like yours). If found, it modifies the MSIL as specified by the attribute. You would have to derive your attribute from a PostSharp base attribute/aspect and then override the appropriate methods. In your case, you would have to derive from the LocationInterceptionAspect and then override the OnSetValue(...) method. In this method you would determine the delegate using the attribute arguments (as given above) and then call this using reflection. "Intercepting Properties and Fields" in the PostSharp documentation gives a very good introduction how to do this.
I think you would end up with something like this:
public class ExecuteDelegateOnPropertySetAspect : LocationInterceptionAspect
{
public ExecuteDelegateOnPropertySetAspect(Type methodOwner, string methodName, object[] arguments)
{
this.MethodOwner = methodOwner;
this.MethodName = methodName;
this.Arguments = arguments;
}
public Type MethodOwner { get; set; }
public string MethodName { get; set; }
public object[] Arguments { get; set; }
public override void OnSetValue(LocationInterceptionArgs args)
{
// get method with the specified name from the specified owner type
MethodInfo method = this.MethodOwner.GetMethod(this.MethodName);
// method must be static, otherwise we would need an instance to call it
if (method != null && method.IsStatic)
{
if (method.GetParameters().Length == this.Arguments.Length)
{
// call the method with the given arguments
method.Invoke(null, this.Arguments);
}
}
// execute the original setter code
args.ProceedSetValue();
}
}
And in your code you would apply this aspect to your properties:
public class Test
{
public static void TestMethod(string someMessage)
{
MessageBox.Show(someMessage);
}
[ExecuteDelegateOnPropertySetAspect(typeof(Test), "TestMethod", new object[] { "Hello world!" })]
public string TestProperty { get; set; }
}
Note that I omitted most of the error and null checking to keep it simple and short.
You seem to have misunderstood the concept of properties in C#.
The properties have a getter and setter function. They will automatically get executed when you set the property or get its value.
So all you need to do is to change the set function of your property to something like this:
public class Test
{
private string _testProperty;
private bool testPropertyIsSet = false;
public string TestProperty
{
get { return this._testProperty; }
set
{
_testProperty = value;
if (!testPropertyIsSet)
{
// Do something here when your property gets set for the first time
}
testPropertyIsSet = true;
}
}
}
Then call it:
public void Run()
{
var test = new Test();
test.TestProperty = "blah";
test.TestProperty = "blah2";
}
I have class named "config" that have private string variable named "param".
I need to get from "config" class "param" variable sometimes as int type sometimes as bool type or string.
As I understand I need create 3 properties in config class,each property have to convert type, as follow:
The first property converts string to int, the second converts string to bool, the third property gets me the string value.
The class should look something like this:
class Config
{
private string param;
public int ParamAsInt
{
get
{
return int.Parse(param);
}
}
public bool ParamAsBool
{
get
{
return bool.Parse(param);
}
}
public string ParamAsString
{
get
{
return param;
}
}
}
But I don't know how can those properties be used in accordance to the variable type that I want to get out of class.
This code won't compile - int and such are reserved keywords and cannot be used as identifiers. You can either try naming your properties something like Int32Value, StringValue, etc., or try this:
public static implicit operator bool (Config config)
{
return bool.Parse(config.param);
}
public static implicit operator int (Config config)
{
return int.Parse(config.param);
}
This will allow for much cleaner code:
Config c = GetConfig("foo");
var isFeatureEnabled = false || c;
var spacing = 23 + GetConfig("bar");
You forgot to give your properties names. How would you expect to reference them? Something like this:
class Config
{
private string param;
public int ParamAsInt
{
get
{
return int.Parse(param);
}
}
public bool ParamAsBool
{
get
{
return bool.Parse(param);
}
}
public string ParamAsString
{
get
{
return param;
}
}
}
Note that I also fixed the casing in your calls to .Parse(). C# is case-sensitive. I also replaced the call to bool.TryParse() with bool.Parse(). The former (when used correctly, which this wasn't because it was missing a parameter) will only tell you if it is a bool, it won't tell you what value the bool actually has. (For example, bool.TryParse('false' out someBool) will return true.)
Of course, this code is a bit dangerous. You'll want to start with some more defensive programming to check those values. Basically, look up TryParse() and how to use it correctly. Something like this, for example:
public int ParamAsInt
{
get
{
var tmp = default(int);
if (int.TryParse(param, out tmp))
return tmp;
else
// do something else? throw a specific exception?
}
}
Additionally, what is the purpose of this code? It seems like a very rushed and poor design. For any given value of param (how is that even being set, by the way?) this just sort of randomly tries to expose typed properties for it. If you guess the correct one, you're still left with others that will throw exceptions. Surely there's a much cleaner way to accomplish what you're trying to do. So what are you trying to do?
I have a custom object called S2kBool that can be converted to and from a regular Boolean object. Basically, it allows my application to treat boolean values in my legacy database the same way it treats C# booleans. Then problem is, when I attempt to use a check box to set the value of an S2kBool property, it fails.
Code like this works:
public class MyClass {
public S2kBool MyProperty { get; set; }
}
MyClassInstance.MyProperty = true;
But it's almost like UpdateModel is expecting an actual bool type, rather than an object that can be converted to a bool. I can't really tell, however, since the exception thrown is so vague:
The model was not successfully updated.
How can I get around this? Do I need a custom ModelBinder?
Thanks!
While Charlino's solution is clever and will work, I personally wouldn't like the idea of "dirtying" up my domain entities with an extra property just for this purpose. I think you had the answer up top already: a custom modelbinder. Something like:
public class S2kBoolAttribute : CustomModelBinderAttribute, IModelBinder
{
public override IModelBinder GetBinder()
{
return this;
}
public object BindModel( ControllerContext controllerContext, ModelBindingContext bindingContext )
{
ValueProviderResult result;
return bindingContext.ValueProvider.TryGetValue( bindingContext.ModelName, out result )
? (S2kBool)result.ConvertTo( typeof( bool ) )
: null;
}
}
And then you can modify your controller action to look like:
public ActionResult Foo( [S2kBool]S2kBool myProperty ){
myClassInstance.MyProperty = myProperty;
SaveToLegacyDb(myClassInstance);
return RedirectToAction("Bar");
}
If you put a bit more work into the modelbinder you could get it to work with the binder being globally registered - but the implementation I gave you above should work for cherry-picking values out when needed.
You could have an additional bool property of type bool that when set changes the value of your S2kBool property.
public class MyClass {
public S2kBool MyProperty { get; set; }
public bool MyPropertyBool {
get
{
return (bool)MyProperty;
}
set
{
MyProperty = value;
}
}
}
You then just have the MyPropertyBool in your html form and the modelbinder won't freak out about it's type.
I use this technique for properties like Password & HashedPassword where Password is the property from the html form that the ModelBinder binds to and in the Password's setter it sets HashedPassword to the hash of it which is then persisted to the database or what ever.