I've created a new configuration file Special.config:
<?xml version="1.0" encoding="utf-8"?>
<SpecialConfig xmlns:config="urn:telerik:sitefinity:configuration" xmlns:type="urn:telerik:sitefinity:configuration:type" config:version="10.0.6401.0">
<UnicornSettings HornSize="#{HornSize}" HoofColor="#{HoofColor}" />
</SpecialConfig>
Then followed the documentation to set up a pair of classes (and register the config in the Global.asax.cs) file:
public class SpecialConfig : ConfigSection
{
public UnicornSettingsElement UnicornSettings
{
get
{
return (UnicornSettingsElement)this["UnicornSettings"];
}
set
{
this["UnicornSettings"] = value;
}
}
}
public class UnicornSettingsElement : ConfigElement
{
public UnicornSettingsElement(ConfigElement parent) : base(parent)
{
}
public String HornSize
{
get
{
return (String)this["HornSize"];
}
set
{
this["HornSize"] = value;
}
}
public String HoofColor
{
get
{
return (String)this["HoofColor"];
}
set
{
this["HoofColor"] = value;
}
}
}
But even after explicitly instantiating SpecialConfig.UnicornSettings, it's still null:
UnicornSettings config = Config.Get<UnicornSettings>();
config.UnicornSettings = new UnicornSettingsElement(config);
config.UnicornSettings.HornSize = HornSize; //<-- config.UnicornSettings is null
config.UnicornSettings.HoofColor = HoofColor;
ConfigManager manager = ConfigManager.GetManager();
manager.SaveSection(config);
I have no idea how to overcome this particular exception where the reference is null immediately after being set. Anyone see what I'm missing?
Update
After further fiddling, I think there's something wrong with the getter or setter on the SpecialConfig.UnicornSettings... I'm not sure what that could be though.
DISCLAIMER
I understand what a null reference exception is, and generally speaking how to identify and overcome a null reference exception. This is not a duplicate of a particular C# question whose answer is a very non-specific book of information. This is a particular and precise case involving a specific framework that warrants its own question.
Forgot the ConfigurationProperties. I'm guessing these are necessary for the way the getter/setter accesses properties:
public class SpecialConfig : ConfigSection
{
[ConfigurationProperty("UnicornSettings")]
public UnicornSettingsElement UnicornSettings
{
get
{
return (UnicornSettingsElement)this["UnicornSettings"];
}
set
{
this["UnicornSettings"] = value;
}
}
}
public class UnicornSettingsElement : ConfigElement
{
public UnicornSettingsElement(ConfigElement parent) : base(parent)
{
}
[ConfigurationProperty("HornSize", IsRequired = true)]
public String HornSize
{
get
{
return (String)this["HornSize"];
}
set
{
this["HornSize"] = value;
}
}
[ConfigurationProperty("HoofColor", IsRequired = true)]
public String HoofColor
{
get
{
return (String)this["HoofColor"];
}
set
{
this["HoofColor"] = value;
}
}
}
Related
I'm trying to deserialize an XML string, where the value of an element, ain't within the scope of my Enum values.
Public enum MyEnum
{
Unknown,
Car,
Bicycle,
Boat
}
[SerializableAttribute()]
public class MyClass
{
private string _id;
private MyEnum _myEnum;
public string ID
{
get { return _id; }
set { _id = value; }
}
public MyEnum EnumValue
{
get { return _myEnum; }
set { _myEnum = value; }
}
public MyClass(string id)
{
this._id = id;
}
public MyClass() : this("") { }
}
If I try to deserialize following string (note Plane as enum value):
<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><MyClass><ID>1234567890123456789</ID><EnumValue>Plane</EnumValue></MyClass>
then my deserialize will thrown an exception, before it even hit my public field for EnumValue, with following exception message:
Instance validation error: 'Plane' is not a valid value for EnumValue
Is it possible to return a default value for EnumValue, if the value I try to parse in the XML ain't supported as a EnumValue??
Eg. in the case of the XML string provided here, the EnumValue should be set as 'Unknown'.
[XmlIgnore]
public MyEnum EnumValueReal
{
get { return _myEnum; }
set { _myEnum = value; }
}
public string EnumValue
{
get
{
return EnumValueReal.ToString();
}
set
{
MyEnum result = MyEnum.Unknown;
Enum.TryParse(value, true, out result);
EnumValueReal = result;
}
}
Other way around would be to declare EnumValue as string and parse value in EnumValue property to MyEnum in another property (with custom logic). Another property should be marked as not serializable.
public string EnumValue
{
get { return _myEnum; }
set { _myEnum = value; }
}
[NonSerialized]
public MyEnum EnumValueTyped {
get {
MyEnum value;
if (Enum.TryParse<MyEnum>(EnumValue, out value)) {
return value;
}
return MyEnum.Unknown;
}
set {
EnumValue = value.ToString();
}
}
Sometimes what happens is we do not take the update of the dlls or the projects we are referring in the project after making changes to the later and hence the parameter added/deleted does not get detected, thus throwing the same issue. Hence better take the updated dll and proceed.Can be a silly mistake but often committed. All the best :)
IMHO the most 'appropriate' solution would be to make EnumValue property nullable - since error you are getting (and MyEnum.Unknown) implies that it is possible for this property not to have a value...
Code would look following:
public enum MyEnum
{
Car,
Bicycle,
Boat
}
[Serializable()]
public class MyClass
{
private string _id;
private MyEnum? _myEnum;
public string ID
{
get { return _id; }
set { _id = value; }
}
public MyEnum? EnumValue
{
get { return _myEnum; }
set { _myEnum = value; }
}
public MyClass(string id)
{
this._id = id;
}
public MyClass() : this("")
{
}
}
Yes, but you can't do it anymore with SerializableAttribute I think.
You should implement ISerializable and provide your own serializer/deserializer. You can use the default serializer (new BinaryFormatter().serializer() e.g), but you have to implement a custom deserialization.
As is well known, CM doesn't support passing a object of complex type through NavigationService like MVVM Light. So I searched for a workaround and did it like this.
There are two viewmodels: MainPageViewModel and SubPageViewModel.
I first defined 3 classes, namely GlobalData, SnapshotCache and StockSnapshot. StockSnapshot is the type of which the object I want to pass between the 2 viewmodels.
public class SnapshotCache : Dictionary<string, StockSnapshot>
{
public StockSnapshot GetFromCache(string key)
{
if (ContainsKey(key))
return this[key];
return null;
}
}
public class GlobalData
{
private GlobalData()
{
}
private static GlobalData _current;
public static GlobalData Current
{
get
{
if (_current == null)
_current = new GlobalData();
return _current;
}
set { _current = value; }
}
private SnapshotCache _cachedStops;
public SnapshotCache Snapshots
{
get
{
if (_cachedStops == null)
_cachedStops = new SnapshotCache();
return _cachedStops;
}
}
}
public class StockSnapshot
{
public string Symbol { get; set; }
public string Message { get; set; }
}
Next, I call the navigation service on MainPageViewModel like this:
StockSnapshot snap = new StockSnapshot {Symbol="1", Message = "The SampleText is here again!" };
GlobalData.Current.Snapshots[snap.Symbol] = snap;
NavigationService.UriFor<SubPageViewModel>().WithParam(p=>p.Symbol,snap.Symbol).Navigate();
And on SubPageViewModel I've got this:
private string _symbol;
public string Symbol
{
get { return _symbol; }
set
{
_symbol = value;
NotifyOfPropertyChange(() => Symbol);
}
}
public StockSnapshot Snapshot
{
get { return GlobalData.Current.Snapshots[Symbol]; }
}
And that's where the problem lies. When I run the program, I find out that it always runs to the getter of Snapshot first, when Symbol hasn't been initialized yet. So later I've tried adding some extra code to eliminate the ArgumentNullException so that it can run to the setter of Symbol and then everything goes fine except that the UI doesn't get updated anyway.
Could anyone tell me where I've got wrong?
Thx in advance!!
Why not just use:
private string _symbol;
public string Symbol
{
get { return _symbol;}
set
{
_symbol = value;
NotifyOfPropertyChange(() => Symbol);
NotifyOfPropertyChange(() => Snapshot);
}
}
public StockSnapshot Snapshot
{
get { return Symbol!=null? GlobalData.Current.Snapshots[Symbol]:null; }
}
In this case you don't try and get the data from GlobalData when Symbol is null (sensible approach anyway!) and when "Symbol" is set you call NotifyOfPropertyChange() on Snapshot to force a re-get of the property.
We use backing fields for a lot of properties on our domain objects, for example:
protected string _firstname;
public virtual string Firstname
{
get { return _firstname; }
set { _firstname = value; }
}
I've occasionally made stupid typos like the example below, and would like to write a single test that verifies all these properties, rather than manually doing a test per object.
public virtual string Firstname
{
get { return _firstname; }
set { _firstname = Firstname; }
}
Would it be easy to write or does a library already exist to test these backing fields get/set correctly? This would only run on properties with setters and (presumably) a backing field that matches the property name using camel-case underscore
Another solution would be to use automatic properties to eliminate this problem:
public virtual string FirstName { get; set; }
UPDATE (see comments, backing field seems needed):
Another possibility is to generate the pocos. Simple t4-template 'Person.tt'
<## template language="C#" #>
<# var pocos = new [] {
Tuple.Create("FirstName", "string"),
Tuple.Create("LastName", "string"),
Tuple.Create("Age", "int")}; #>
public partial class Person {
<# foreach(var t in pocos) {#>
protected <#= t.Item2#> _<#= t.Item1.ToLowerInvariant()#>;
public virtual <#= t.Item2#> <#= t.Item1#>
{
get { return _<#= t.Item1.ToLowerInvariant()#>; }
set { _<#= t.Item1.ToLowerInvariant()#> = value; }
}
<#}#>
}
Now this could of course bring with it as many problems as it solves but it may be worth looking at ... maybe:)
Apart from using auto properties I would think of using reflection to test out my models.. .
Just write a generic method that gets all the properties of your class and then use methods like these:
/ get value of property: public double Number
double value = (double)numberPropertyInfo.GetValue(calcInstance, null);
[C#]
// set value of property: public double Number
numberPropertyInfo.SetValue(calcInstance, 10.0, null);
For your example:
void Main()
{
const int testValue=5;
var test = (Test)Activator.CreateInstance(typeof(Test));
PropertyInfo valuePropertyInfo = typeof(Test).GetProperty("Value");
valuePropertyInfo.SetValue(test, testValue, null);
int value = (int)valuePropertyInfo.GetValue(test, null);
Console.Write(value); //Assert here instead
}
public class Test
{
private int _value;
public int Value {get {return _value;} set{_value=Value;}}
}
the output of the above function is 0 instead of a 5 which is expected. asserting here would have thrown an error.
What do you think about this approach.
Gallio/MbUnit has a contract verifier which does exactly what you are looking for. A typical usage of AccessContract is the following:
public class Foo // Dummy reference type.
{
private readonly int value;
public int Value { get { return value; } }
public Foo (int value)
{
this.value = value;
}
}
public class Bar
{
private Foo foo;
public Bar(string unusedParameter) { }
public Foo Foo // A complex property to be tested!
{
get { return foo; }
set
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Value < 0)
throw new ArgumentOutOfRangeException();
if (value.Value == 666)
throw new ArgumentException("Inferno value strictly forbidden.");
foo = value;
}
}
}
And the test fixture which uses AccessorContract to run various tests on the property.
[TestFixture]
public class BarTest
{
[VerifyContract]
public readonly IContract AccessorTests = new AccessorContract<Bar, Foo>
{
Getter = target => target.Foo,
Setter = (target, value) => target.Foo = value,
ValidValues = { new Foo(123), new Foo(456), new Foo(789) },
AcceptNullValue = false,
DefaultInstance = () => new Bar("Hello"),
InvalidValues =
{
{ typeof(ArgumentOutOfRangeException), new Foo(-123), new Foo(-456) },
{ typeof(ArgumentException), new Foo(666) }
}
};
}
The contract verifier generates the following unit tests:
Have a look at the MbUnit test project for more usage examples.
Does someone know library, that reduces amounts of boilerplate code when writing object proxies?
My proxies right now look the following way and I think it's a nasty approach :)
public class SampleTenantProxy : Tenant
{
public override int? Id
{
get { return tenant.Id; }
set { tenant.Id = value; }
}
public override String Code
{
get { return tenant.Code; }
set { tenant.Code = value; }
}
public override String Name
{
get { return tenant.Name; }
set { tenant.Name = value; }
}
public override Decimal Price
{
get { return tenant.Price; }
set { tenant.Price = value; }
}
private readonly Tenant tenant;
public TenantListBoxProxy(Tenant tenant)
{
this.tenant = tenant;
}
}
Most Dependency Injection tools (such as Windsor Castle - have a look here) can do it.
Castle Dynamic Proxy -> http://www.castleproject.org/dynamicproxy/index.html
I have a class that represents a configuration element:
public class ProductLevelConfigurationElement
: ConfigurationElement, IProductLevelConfiguration
{
[ConfigurationProperty("level",IsKey = true, IsRequired = true)]
public ProductLevel Level
{
get { return (ProductLevel)this["level"]; }
set { this["level"] = value; }
}
[ConfigurationProperty("include")]
public bool Include
{
get { return (bool)this["include"]; }
set { this["include"] = value; }
}
}
In web.config I want to configure it like:
<item level="1" include="true" />
But it doesn't work. If I put MainProduct in level attribute (one of the values of this enum) then it works perfect.
Any thoughts on how to solve this?
You can hack around it by changing your configuration property to type int, making it private and create a new property on your class.
[ConfigurationProperty("level", IsKey = true, IsRequired = true)]
private int LevelFromConfig
{
get { return (int)this["level"]; }
set { this["level"] = value; }
}
public ProductLevel Level
{
get { return (ProductLevel)this.LevelFromConfig; }
}
The above code is provided as a simple example with no error checking of any kind.
I have found solution.
You can override DeserializeElement method
protected override void DeserializeElement(System.Xml.XmlReader reader, bool serializeCollectionKey)
{
Level = (ProductLevel) int.Parse(reader.GetAttribute("level"));
}