I am having trouble with a piece of old code that I need to amend, I have added the Metadata property but cannot expose it, the code is simple.
public interface IBigThing : IList<ILittleThing>
{
string Metadata { get; set; }
}
[Serializable]
public class BigThing: List<ILittleThing>, IBigThing , ISerializable
{
string m_Metadata;
[DataMember]
public string Metadata
{
get { return m_Metadata; }
set { m_Metadata = value; }
}
#region Constructors
public BigThing()
{ }
public BigThing(string p_Metadata)
{
Metadata = p_Metadata;
}
#endregion
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Metadata", Metadata);
}
}
When I inspect the app or serialize to json, the Metadata is ignored and can only be accessed if explicitly called.
IBigThing toReturn = new BigThingFactory.Manufacture();
string strJson = new JavaScriptSerializer().Serialize(toReturn);
Im sure I am missing something simple, can anyone help please?
Add the [DataMember] attribute to the property definition in IBigThing. The serialization framework only analyses the types that you tell it about and therefore will not see any declarations in BigThing.
Related
I have an interface with multiple implementations:
public enum Source { Source1, Source2 }
public interface IMessageClient
{
Source Source { get; }
Response<string[]> GetMessages();
Response<string> GetMessage();
}
public class Response<T>
{
public Source Source { get; set;}
public T Data { get; set; }
}
I would like to decorate my responses with the type/source of the messages (currently Source above), without explicitly setting it in all of my response methods, i.e. setting in on each Response instance manually. Is that possible?
public class MessageClient : IMessageClient
{
public Source Source => Source.Source1;
public Response<string[]> GetMessages()
{
return new Response<string[]>
{
Source = Source, Data = new[] {"1", "2"}
};
}
public Response<string> GetMessage()
{
throw new NotImplementedException();
}
}
To elaborate, currently I need to set Source manually on each response. What are my options as far as automating that goes? I just want it decorated from the containing class without explicitly setting it on each response.
I think (hope) I got it.
Can you inherit from a base class?
public abstract class BaseMessageClient : IMessageClient
{
public Source Source { get; protected set; }
public Response<T> CreateResponse(T data)
{
return new .... Source = this.Source ...
}
...
}
Or you can put the CreateResponse into the interface with a default implementation (since .NET 5 afair). Down side: I think you always need a cast to the interface.
(this as IMessageClient).CreateResponse(data)
[EDIT] Remark: All parameters that are needed to create a valid Response could be params for the constructor. In this case I like the new records.
public record Response<T>(Source Source, T Data);
I am trying to implement a method that get's called on deserializing a custom component.
However, the methods marked as OnDeserializing and OnDeserialized are never called.
I found this question on SO and from the text I conclude that here these method's are being called. So I compared this code with mine.
Also in the documentation I cannot see anything that I am missing.
What I need is that when my custom component is deserializing from the Designer.cs on designtime, I can step in and do some extra coding.
So what am I missing here ?
[Serializable]
public partial class gttDataTable : Component, ISerializable
{
private Collection<ConfigColumn> _columns = new Collection<ConfigColumn>();
public gttDataTable()
{ }
public gttDataTable(SerializationInfo info, StreamingContext context)
{ }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Collection<ConfigColumn> gttColumns
{
get { return _columns; }
set { _columns = value; }
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
// this code is never called
throw new NotImplementedException();
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
// this code is never called
throw new NotImplementedException();
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
// this code is never called
throw new NotImplementedException();
}
private IComponentChangeService GetChangeService()
{
return (IComponentChangeService)GetService(typeof(IComponentChangeService));
}
}
public class ConfigColumn
{
public string Name { get; set; }
public string Caption { get; set; }
public string ColumnName { get; set; }
public Type DataType { get; set; }
}
EDIT
For clarity, the problem is that both the internal methods are never called when the custom component is deseriazeling.
EDIT 2
I tried making the internal methods public, as suggested, but it makes no difference. They still are not called
EDIT 3
I read this link and doublechecked that all is the same as in the documetation. In my opinion it is all correct, but still the methods are not called
Not all serializer take into consideration such attribute as OnDeserializing etc. see e.g. Why does the OnDeserialization not fire for XML Deserialization?.
If I'm not mistaken designer does use CodeDomSerializer.
To make custom serailization you need to derive from CodeDomSerializer and decorate the class with DesignerSerializerAttribute
[DesignerSerializerAttribute(typeof(YourCustomSerializer), typeof(CodeDomSerializer))]
public partial class gttDataTable : Component
{
}
I'm reading some code, can you please explain what the below line does?
bool isFeatureEnabled = FeatureControl.Current.Features.AppDesigner.IsEnabled(organizationId,currentOrgDBVersion);
Here's the definitions of the above code
public sealed class FeatureControl : IFeatureControl
{
public static IFeatureControl Current { get; }
[XmlIgnore]
public IFeatureDetailContainer Features { get; set; }
....
}
public interface IFeatureControl
{
IFeatureDetailContainer Features { get; set; }
...
}
public interface IFeatureDetailContainer
{
IFeatureDetail AppDesigner { get; }
}
public interface IFeatureDetail
{
bool IsEnabled(Guid organizationId, Version currentOrgDBVersion);
}
I don't see any instances created, how does this work?
Sorry, I copied metadata, I just found the actual code:
public sealed class FeatureControl : IFeatureControl
{
private static readonly Lazy<IFeatureControl> current = new Lazy<IFeatureControl>(() => new FeatureControl());
private IFeatureDetailContainer features;
public static IFeatureControl Current
{
get
{
return current.Value;
}
}
/// <summary>
/// Accessor to the Features List for Developers to retrieve the information
/// </summary>
[XmlIgnore]
public IFeatureDetailContainer Features
{
get
{
return this.features;
}
set
{
this.features = value;
}
}
}
It is a singleton pattern. Normally, the instance is created inside constructor.
public interface IFeatureControl { }
public sealed class FeatureControl : IFeatureControl
{
public static IFeatureControl Current { get; }
static FeatureControl()
{
if (Current == null)
{
Current = new FeatureControl();
}
}
}
[TestFixture]
public class FeatureControlTests
{
[Test]
public void IsFeatureControlSingleton()
{
IFeatureControl c1 = FeatureControl.Current;
IFeatureControl c2 = FeatureControl.Current;
Assert.AreSame(c1, c2);
}
}
At some point in the code (not shown here) you can expect the object IFeatureControl::Current is being created / new'd.
Your line of code is merely accessing that value. Note that if you run the code without actually instantiating the Current object you'll get a null ref. error.
You can program an elaborate set of code using Interfaces and the code will compile and look great, however if none of the interface objects are instantiated with new'd instances of classes that inherit from the Interface you'll get null reference exceptions.
Consider the use of interfaces in this example an outline for how things WILL be arranged and how they WILL operate. However it's just an outline and you'll need to colour inside the lines to actually achieve an outcome.
Good luck!
I want to pass a class to a client over a WCF service. In that class I use a struct. But the value I receive at client side is: "System.Data.DataSet"
Must be something I don't understand.
See my struct (it's just a string for now)
namespace spine.datatypes
{
[Serializable]
public struct Tanga : IXmlSerializable
{
private string _value;
public Tanga(string value)
{
this._value = value;
}
public static implicit operator Tanga(string value)
{
return new Tanga(value);
}
public override string ToString()
{
return this._value;
}
// implement IXmlSerializable
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
_value = reader.ReadContentAsString();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteValue(this._value.ToString());
}
}
}
This is my service:
namespace webapplication.WCFservice.Recorder
{
[ServiceContract]
[XmlSerializerFormat]
public interface IWCFRecorder
{
[OperationContract]
TvRecorder getDedicatedJob(String recordername, String recorderip);
}
}
And this is the class I pass:
namespace spine.recorder.tv
{
[Serializable()]
[XmlRoot("Recorder")]
public class TvRecorder
{
public int id { get; set; }
public Tanga name { get; set; }
public MyIpAddress ip { get; set; }
public int channel { get; set; }
public MyTimecode time_start { get; set; }
public MyTimecode duration { get; set; }
public TvRecorder() { }
public TvRecorder(int _id, Tanga _name, MyIpAddress _ip, int _channel, MyTimecode _time_start, MyTimecode _duration)
{
this.id = _id;
this.name = _name;
this.ip = _ip;
this.channel = _channel;
this.time_start = _time_start;
this.duration = _duration;
}
}
}
There are unfortunately cases where svcutil generates a DataContract type and an XmlSerializer type for the same schema type. I suggest you try using the additional “/serializer:XmlSerializer /useSerializerForFaults” switches to svcutil and see if that resolves your issue. It should ensure that Tanga gets generated.
In general, for schema import to generate DataContract types, all of the types defined in the schemas must be contained in the subset of XSD that DCS supports, which you can find here:
http://msdn.microsoft.com/en-us/library/ms733112.aspx
If svcutil is failing to generate a proxy when you specify “/serializer:DataContractSerializer”, then the most likely explanation is that the schema isn’t DC-conformant. Do you see any other errors or warnings when you use svcutil?
It’s also generally bad practice to use DataSets (both typed and untyped) and IXmlSerializables in public web services. In this case, it seems there might be difficulties in importing these. Here’s a quick link for some other reasons it can be problematic: http://www.hanselman.com/blog/PermaLink,guid,d88f7539-10d8-4697-8c6e-1badb08bb3f5.aspx
While DataContractSerializer can serialize IXmlSerializable types, there is no guarantee at all made that IXmlSerializable types can be imported as data contracts. Those are two different concepts. IXmlSerializable types are free to provide their own schemas, so it's possible for them to provide schemas that are not datacontract-compliant and thus cause svcutil to fall back to XmlSerializer type generation.
Hope this helps.
I have a project where I need to construct a fair amount of configuration data before I can execute a process. During the configuration stage, it's very convenient to have the data as mutable. However, once configuration has been completed, I'd like to pass an immutable view of that data to the functional process, as that process will rely on configuration immutability for many of its computations (for instance, the ability to pre-compute things based on initial configuration.) I've come up with a possible solution using interfaces to expose a read-only view, but I'd like to know if anybody has encountered problems with this type of approach or if there are other recommendations for how to solve this problem.
One example of the pattern I'm currently using:
public interface IConfiguration
{
string Version { get; }
string VersionTag { get; }
IEnumerable<IDeviceDescriptor> Devices { get; }
IEnumerable<ICommandDescriptor> Commands { get; }
}
[DataContract]
public sealed class Configuration : IConfiguration
{
[DataMember]
public string Version { get; set; }
[DataMember]
public string VersionTag { get; set; }
[DataMember]
public List<DeviceDescriptor> Devices { get; private set; }
[DataMember]
public List<CommandDescriptor> Commands { get; private set; }
IEnumerable<IDeviceDescriptor> IConfiguration.Devices
{
get { return Devices.Cast<IDeviceDescriptor>(); }
}
IEnumerable<ICommandDescriptor> IConfiguration.Commands
{
get { return Commands.Cast<ICommandDescriptor>(); }
}
public Configuration()
{
Devices = new List<DeviceDescriptor>();
Commands = new List<CommandDescriptor>();
}
}
EDIT
Based on input from Mr. Lippert and cdhowie, I put together the following (removed some properties to simplify):
[DataContract]
public sealed class Configuration
{
private const string InstanceFrozen = "Instance is frozen";
private Data _data = new Data();
private bool _frozen;
[DataMember]
public string Version
{
get { return _data.Version; }
set
{
if (_frozen) throw new InvalidOperationException(InstanceFrozen);
_data.Version = value;
}
}
[DataMember]
public IList<DeviceDescriptor> Devices
{
get { return _data.Devices; }
private set { _data.Devices.AddRange(value); }
}
public IConfiguration Freeze()
{
if (!_frozen)
{
_frozen = true;
_data.Devices.Freeze();
foreach (var device in _data.Devices)
device.Freeze();
}
return _data;
}
[OnDeserializing]
private void OnDeserializing(StreamingContext context)
{
_data = new Data();
}
private sealed class Data : IConfiguration
{
private readonly FreezableList<DeviceDescriptor> _devices = new FreezableList<DeviceDescriptor>();
public string Version { get; set; }
public FreezableList<DeviceDescriptor> Devices
{
get { return _devices; }
}
IEnumerable<IDeviceDescriptor> IConfiguration.Devices
{
get { return _devices.Select(d => d.Freeze()); }
}
}
}
FreezableList<T> is, as you would expect, a freezable implementation of IList<T>. This gains insulation benefits, at the cost of some additional complexity.
The approach you describe works great if the "client" (the consumer of the interface) and the "server" (the provider of the class) have a mutual agreement that:
the client will be polite and not try to take advantage of the implementation details of the server
the server will be polite and not mutate the object after the client has a reference to it.
If you do not have a good working relationship between the people writing the client and the people writing the server then things go pear-shaped quickly. A rude client can of course "cast away" the immutability by casting to the public Configuration type. A rude server can hand out an immutable view and then mutate the object when the client least expects it.
A nice approach is to prevent the client from ever seeing the mutable type:
public interface IReadOnly { ... }
public abstract class Frobber : IReadOnly
{
private Frobber() {}
public class sealed FrobBuilder
{
private bool valid = true;
private RealFrobber real = new RealFrobber();
public void Mutate(...) { if (!valid) throw ... }
public IReadOnly Complete { valid = false; return real; }
}
private sealed class RealFrobber : Frobber { ... }
}
Now if you want to create and mutate a Frobber, you can make a Frobber.FrobBuilder. When you're done your mutations, you call Complete and get a read-only interface. (And then the builder becomes invalid.) Since all the mutability implementation details are hidden in a private nested class, you can't "cast away" the IReadOnly interface to RealFrobber, only to Frobber, which has no public methods!
Nor can the hostile client create their own Frobber, because Frobber is abstract and has a private constructor. The only way to make a Frobber is via the builder.
This will work, but "malicious" methods may try to cast an IConfiguration to a Configuration and thereby bypass your interface-imposed restrictions. If you're not worried about that then your approach will work fine.
I usually do something like this:
public class Foo {
private bool frozen = false;
private string something;
public string Something {
get { return something; }
set {
if (frozen)
throw new InvalidOperationException("Object is frozen.");
// validate value
something = value;
}
}
public void Freeze() {
frozen = true;
}
}
Alternatively, you could deep-clone your mutable classes into immutable classes.
Why can't you provide a separate immutable view of the object?
public class ImmutableConfiguration {
private Configuration _config;
public ImmutableConfiguration(Configuration config) { _config = config; }
public string Version { get { return _config.Version; } }
}
or if you don't like the extra typing, make the set members internal rather than public - accessible within the assembly but not by clients of it?
I'm regularly working with a large, COM-based framework (ESRI's ArcGIS Engine) that handles modifications very similarly in some situations: there are the "default" IFoo interfaces for read-only access, and IFooEdit interfaces (where applicable) for modifications.
That framework is fairly well-known, and I'm not aware of any widespread complaints about this particular design decision behind it.
Finally, I think it's definitely worth some additional thought in deciding which "perspective" gets to be the default one: the read-only perspective or the full-access one. I would personally make the read-only view the default.
How about:
struct Readonly<T>
{
private T _value;
private bool _hasValue;
public T Value
{
get
{
if (!_hasValue)
throw new InvalidOperationException();
return _value;
}
set
{
if (_hasValue)
throw new InvalidOperationException();
_value = value;
}
}
}
[DataContract]
public sealed class Configuration
{
private Readonly<string> _version;
[DataMember]
public string Version
{
get { return _version.Value; }
set { _version.Value = value; }
}
}
I called it Readonly but I'm not sure that's the best name for it though.