JsonConvert.SerializeObject ignores subtype - json.net

I'm using JsonConvert to serialize an object like so:
JsonConvert.SerializeObject(item)
Item is an instance of QuestionExtendedView, which looks like this:
public class QuestionExtendedView : AuditFullView
{
public short QuestionNo { get; set; }
public short TotalQuestions { get; set; }
public short UnansQuestions { get; set; }
}
AuditFullView looks like this:
public partial class AuditFullView : EntityObject
{
public static AuditFullView CreateAuditFullView(global::System.Int32 hAA_ID, global::System.Int16 hAA_Branch, global::System.Int32 hAA_AuditorID, global::System.DateTime hAA_ScheduledDate, global::System.Int32 hAA_TemplateVersionID, global::System.String hAA_Status, global::System.Int32 hAS_ID, global::System.Int32 hAS_AuditID, global::System.Int32 hAS_TemplateSectionID, global::System.Int32 hAE_ID, global::System.Int32 hAE_AuditID, global::System.Int32 hAE_HAS_ID, global::System.Int32 hAE_TemplateElementID, global::System.Int16 hAE_ScriptSequence, global::System.Int32 hAQ_ID, global::System.Int32 hAQ_AuditID, global::System.Int32 hAQ_HAE_ID, global::System.Int32 hAQ_TemplateQuestionID, global::System.Int16 hAQ_ScriptSequence, global::System.Int32 hTS_ID, global::System.Int32 hTS_VersionID, global::System.Int32 hTS_Sequence, global::System.String hTS_SectionName, global::System.Int32 hTE_ID, global::System.Int32 hTE_SectionID, global::System.Int32 hTE_Sequence, global::System.String hTE_Element, global::System.String hTE_Objective, global::System.String hTE_Guidance, global::System.Int32 hTQ_ID, global::System.Int32 hTQ_ElementID, global::System.Int32 hTQ_Sequence, global::System.String hTQ_Question, global::System.Boolean hTQ_WeightedQuestion, global::System.String hSU_Name, global::System.Boolean hAQ_PreviouslyAnsweredQuestion)
{
AuditFullView auditFullView = new AuditFullView();
auditFullView.HAA_ID = hAA_ID;
auditFullView.HAA_Branch = hAA_Branch;
// Loads of properties excluded for clarity
return auditFullView;
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 HAA_ID
{
get
{
return _HAA_ID;
}
set
{
if (_HAA_ID != value)
{
OnHAA_IDChanging(value);
ReportPropertyChanging("HAA_ID");
_HAA_ID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("HAA_ID");
OnHAA_IDChanged();
}
}
}
private global::System.Int32 _HAA_ID;
partial void OnHAA_IDChanging(global::System.Int32 value);
partial void OnHAA_IDChanged();
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int16 HAA_Branch
{
get
{
return _HAA_Branch;
}
set
{
if (_HAA_Branch != value)
{
OnHAA_BranchChanging(value);
ReportPropertyChanging("HAA_Branch");
_HAA_Branch = StructuralObject.SetValidValue(value);
ReportPropertyChanged("HAA_Branch");
OnHAA_BranchChanged();
}
}
}
private global::System.Int16 _HAA_Branch;
partial void OnHAA_BranchChanging(global::System.Int16 value);
partial void OnHAA_BranchChanged();
// Loads of properties excluded for clarity
}
Now, when I run this serialization, I get all the properties from AuditFullView, but not the ones from QuestionExtendedView, as shown with this test:
[TestMethod]
public void CanSerialize()
{
QuestionExtendedView myView = new QuestionExtendedView
{
TotalQuestions = 15,
QuestionNo = 10,
UnansQuestions = 5,
HAA_ID = 100,
HAA_Branch = 213
};
string json = JsonConvert.SerializeObject(myView);
json.Should().Contain("TotalQuestions");
}
Which fails as the result is:
{"$id":"1","HAA_ID":100,"HAA_Branch":213,"EntityKey":null}
(again, I have excluded lots of properties from AuditFullView for clarity)
I even tried this:
JsonConvert.SerializeObject(Convert.ChangeType(myView, typeof(QuestionExtendedView))
No difference though. I can't seem to find other people having this issue. Am I missing something?

Your AuditFullView class inherits from EntityObject, which is marked with a DataContract attribute. Because of this, JSON.NET requires that all properties must opt-in to serialization using DataMember attributes. Any properties without the attribute will be ignored by the serializer.
The properties on AuditFullView are marked with DataMember, so they're included when serializing; the properties on QuestionExtendedView aren't marked with DataMember, so they're ignored.
So the straightforward solution is to mark-up the properties of your QuestionExtendedView class with DataMember attributes.

Related

Refit inheritance misses methods

We use Refit for our API declarations and want to use Interface inheritance.
A sample is shown here: https://github.com/reactiveui/refit#interface-inheritance
public interface IPlatformRestClient
{
HttpClient Client { get; }
[Get("/version")]
Task<string> GetVersion();
}
public interface ITestRestClient : IPlatformRestClient
{
[Get("/test")]
Task<string> Test();
}
I may be blind and do something wrong, but the construct results in the following error message
'AutoGeneratedITestRestClient' does not implement interface member 'IPlatformRestClient.GetVersion()' Platform.RestClient.UnitTests
And if I open the stubs:
/// <inheritdoc />
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.Diagnostics.DebuggerNonUserCode]
[Preserve]
[global::System.Reflection.Obfuscation(Exclude=true)]
partial class AutoGeneratedITestRestClient : ITestRestClient
{
/// <inheritdoc />
public HttpClient Client { get; protected set; }
readonly IRequestBuilder requestBuilder;
/// <inheritdoc />
public AutoGeneratedITestRestClient(HttpClient client, IRequestBuilder requestBuilder)
{
Client = client;
this.requestBuilder = requestBuilder;
}
/// <inheritdoc />
Task<string> ITestRestClient.Test()
{
var arguments = new object[] { };
var func = requestBuilder.BuildRestResultFuncForMethod("Test", new Type[] { });
return (Task<string>)func(Client, arguments);
}
}
So is this feature broken or do I have any error?

Ninject Dependency Injection works for only for one controller

I had originally set up DI with ninject for an asp.net web api 2 service with a single controller and everything was working correctly. Upon adding a second controller, ninject does not work for the new one. I'm getting the following error:
"An error occurred when trying to create a controller of type 'VstsController'. Make sure that the controller has a parameterless public constructor."
First controller (for which ninject works):
public class RepositoryController : ApiController
{
private GitHubClient _client;
public RepositoryController(IGitHubClientAuthenticated gitHubClientAuthenticated)
{
_client = gitHubClientAuthenticated.Client;
_client.Credentials = gitHubClientAuthenticated.Credentials;
}
Second controller:
public class VstsController : ApiController
{
private VssConnection _connection;
public VstsController(IVssConnectionAuthenticated vssConnectionAuthenticated)
{
_connection = vssConnectionAuthenticated.VssConnection;
}
Ninject config file:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IVssConnectionAuthenticated>().To<VssConnectionAuthenticated>();
kernel.Bind<IGitHubClientAuthenticated>().To<GitHubClientAuthenticated>();
kernel.Bind<IAuthenticationHelper>().To<AuthenticationHelper>();
}
Do I need to tweak anything if I want to keep adding controllers? Couldn't find any documentation on this. Thanks in advance
EDIT: Including ninject set up code as well as VssAuthenticated + IvssAuthenticated:
namespace Dashboard.WebAPI.Models
{
public interface IVssConnectionAuthenticated
{
VssConnection VssConnection { get; }
Uri Uri { get; }
}
}
namespace Dashboard.WebAPI.Models
{
public class VssConnectionAuthenticated: IVssConnectionAuthenticated
{
public VssConnection VssConnection { get; private set; }
public Uri Uri { get; private set; }
VssConnectionAuthenticated()
{
Uri = new Uri("uri");
string vstsSecretUri = "vstssecreturi";
GetKeyVaultSecret keyVaultSecretGetter = new GetKeyVaultSecret(new AuthenticationHelper(), vstsSecretUri);
string keyVaultSecret = keyVaultSecretGetter.KeyVaultSecret;
VssBasicCredential vssBasicCredential = new VssBasicCredential(string.Empty, keyVaultSecret);
VssConnection = new VssConnection(Uri, vssBasicCredential);
}
Full Ninject Config File:
namespace Dashboard.WebAPI.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using System.Web.Http;
using Dashboard.WebAPI.Models;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage the application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load modules and register services
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IVssConnectionAuthenticated>().To<VssConnectionAuthenticated>();
kernel.Bind<IGitHubClientAuthenticated>().To<GitHubClientAuthenticated>();
kernel.Bind<IAuthenticationHelper>().To<AuthenticationHelper>();
}
}
}
Registering Ninject as Dependency Resolver:
namespace Dashboard.WebAPI.App_Start
{
public class NinjectDependencyScope : IDependencyScope
{
IResolutionRoot resolver;
public NinjectDependencyScope(IResolutionRoot resolver)
{
this.resolver = resolver;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.TryGet(serviceType);
}
public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.GetAll(serviceType);
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
}
public class NinjectDependencyResolver: NinjectDependencyScope, IDependencyResolver
{
IKernel kernel;
public NinjectDependencyResolver(IKernel kernel) : base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
}
In case anyone else runs into this problem- The problem was in VssConnectionAuthenticated: The constructor needs to be public.

Should Mock<SomeClassType>.SetupAllProperties() cause properties to return the values they are assigned?

When I use SetupAllProperties on a Mock, it works as expected:
/// <summary>
/// demos SetupAllProprties on an interface. This seems to work fine.
/// </summary>
[Test]
public void Demo_SetupAllProperties_forAnInterface()
{
var mock = new Mock<IAddress>();
mock.SetupAllProperties();
var stub = mock.Object;
stub.City = "blahsville";
var retrievedCity = stub.City;
Assert.AreEqual("blahsville", retrievedCity);
}
However, when I try it on a class, it fails:
/// <summary>
/// demos SetupAllProprties on a class. This seems to work fine for mocking interfaces, but not classes. :( The Get accessor returns null even after setting a property.
/// </summary>
[Test]
public void Demo_SetupAllProperties_forAClass()
{
var mock = new Mock<Address>();
mock.SetupAllProperties();
var stub = mock.Object;
stub.City = "blahsville";
var retrievedCity = stub.City;
Assert.AreEqual("blahsville", retrievedCity);
}
Did I do something wrong? Am I trying to do something unsupported by moq?
For good measure, here are the IAddress interface and the Address class:
public interface IAddress
{
string City { get; set; }
string State { get; set; }
void SomeMethod(string arg1, string arg2);
string GetFormattedAddress();
}
public class Address : IAddress
{
#region IAddress Members
public virtual string City { get; set; }
public virtual string State { get; set; }
public virtual string GetFormattedAddress()
{
return City + ", " + State;
}
public virtual void SomeMethod(string arg1, string arg2)
{
// blah!
}
#endregion
}
I copied your code into a new project could not reproduce your problem. I set a breakpoint in Demo_SetupAllProperties_forAClass() at the Assert.AreEqual line and retrievedCity did have the value "blahsville".
I am using xUnit, but I don't think that would make a difference. What version of Moq are you using? I am using 4.0.10510.6.

MVMLight Messaging and Silverlight

I am trying to get a sample to work using MVVM Light and the Messaging Class. In the sample, I have a test project created from the MVVM Template for Silveright 4. I have added a button on the main page. When the button is clicked, it updates a property on the ViewModel. When the property is updated, I want to show a messagebox with the new value.
The key line of code is:
Messenger.Default.Register(this, new Action(ShowMessage));
I can get this to work in WPF, but not silverlight. It should call ShowMessage with the string parameter when the property changes, but it does not. If I use:
Messenger.Default.Send("Hello MVVM");
This works and the string is sent as a message to ShowMessage.
However, the message does not get sent if the property changes, even though the property was created with the MVVMINPC snippet and has the following line:
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
This should have the same effect as Messager.Default.Send but it seems to be ignored. ThePropertyChangedEvent is indeed raised, but the messanger part seems to be disconnected.
Am I doing something wrong? Here is the full MainViewModel:
public class MainViewModel : ViewModelBase
{
public RelayCommand MyRelayCommand { get; set; }
public const string MyPropertyPropertyName = "MyProperty";
private string _myProperty = "test";
public string MyProperty
{
get
{
return _myProperty;
}
set
{
if (_myProperty == value)
{
return;
}
var oldValue = _myProperty;
_myProperty = value;
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
}
}
public void DoSomething()
{
//Messenger.Default.Send("Hello MVVM"); //Works
this.MyProperty = "Hello World"; //Doesn't work.
}
public void ShowMessage(string message)
{
MessageBox.Show(message);
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
Messenger.Default.Register(this, new Action<string>(ShowMessage));
MyRelayCommand = new RelayCommand(new Action(DoSomething));
this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MainViewModel_PropertyChanged);
}
void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
MessageBox.Show(e.PropertyName);
}
}public class MainViewModel : ViewModelBase
{
public RelayCommand MyRelayCommand { get; set; }
public const string MyPropertyPropertyName = "MyProperty";
private string _myProperty = "test";
public string MyProperty
{
get
{
return _myProperty;
}
set
{
if (_myProperty == value)
{
return;
}
var oldValue = _myProperty;
_myProperty = value;
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
}
}
public void DoSomething()
{
//Messenger.Default.Send("Hello MVVM"); //Works
this.MyProperty = "Hello World"; //Doesn't work.
}
public void ShowMessage(string message)
{
MessageBox.Show(message);
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
Messenger.Default.Register(this, new Action<string>(ShowMessage));
MyRelayCommand = new RelayCommand(new Action(DoSomething));
this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MainViewModel_PropertyChanged);
}
void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
MessageBox.Show(e.PropertyName);
}
}v
OK, I found that the Register line should look like this:
Messenger.Default.Register(this, new Action<PropertyChangedMessage<string>>(ShowMessage));
The point being there are different types of messages, and you have to register the PropertyChangedMessage type to recieve property changed messages.
Then also, the Action that recieves the message needs to take the correct parameter, like this:
public void ShowMessage(PropertyChangedMessage<string> e)
{
MessageBox.Show(e.NewValue.ToString());
}

asp.net + How to create custom multi-templated tree databound control?

I dont want to use asp.net's TreeView control.
I want to create a custom template databound control with multi template support like -
<asp:MtNavigationControl>
<ItemTemplate>
...
...
</ItemTemplate>
<SelectedItemTemplate>
...
...
</SelectedItemTemplate>
<ParentItemTemplate>
...
...
</ParentSelectedItemTemplate>
<SelectedParentItemTemplate>
...
...
</SelectedParentSelectedItemTemplate>
</asp:MtNavigationControl>
My data is like -
class Employee
{
string EmployeeName
List<Employee> Employees
}
Does anyone know how to accomplish it? Please help !!!
Damn, I thought I might have found what I was looking for. I have the same question and I have it NEARLY complete. I am not sure if it is my class (TreeBranches) or the below class. Seems to work great on the initial render. But then each postback it seems to render things twice. I have tried things like Controls.Clear() but the .UniqueID's seem to always be for a second set of control.
Basically, my TreeBranches is just a collection class for Branch objects. Quite similar to your Employee example. The Template is nothing more than the following:
<h2><a href='<%= this.NavigationUrl %>'><%= this.Title %></a></h2>
<asp:PlaceHolder ID="phContents" runat="server" EnableViewState="true"></asp:PlaceHolder>
It will generate a UL with LI's below them. And if there is a nested Branch, a new UL will be contained in the LI that is the parent. This can be as deep as possible.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.ComponentModel;
using System.Collections;
namespace Website.Controls {
public partial class HeirarchicalList : System.Web.UI.UserControl {
private ITemplate _layoutTemplate = null;
private ITemplate _itemTemplate = null;
private string _LayoutPlaceholderID = "";
#region Public Properties
public TreeBranches DataSource { get; set; }
/// <summary>
/// Gets or Sets the Header for this controls <h2> element.
/// </summary>
[PersistenceMode(PersistenceMode.Attribute)]
public string Title { get; set; }
/// <summary>
/// Gets or Sets the Class name for the outermost LayoutTemplate item.
/// </summary>
[PersistenceMode(PersistenceMode.Attribute)]
public string RootClass { get; set; }
/// <summary>
/// Gets or Sets the Headers link for this controls <h2> element.
/// </summary>
[PersistenceMode(PersistenceMode.Attribute)]
public string NavigationUrl { get; set; }
/// <summary>
/// Gets or Sets the local ID for the LayoutTemplates Placeholder control. Defaults to "layoutPlaceholder"
/// </summary>
[PersistenceMode(PersistenceMode.Attribute)]
public string LayoutPlaceholderID {
get { return string.IsNullOrWhiteSpace(this._LayoutPlaceholderID) ? "layoutPlaceholder" : this._LayoutPlaceholderID; }
set { this._LayoutPlaceholderID = value; }
}
[Browsable(false)]
[DefaultValue(null)]
[TemplateContainer(typeof(LayoutContainer))]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate LayoutTemplate {
get { return _layoutTemplate; }
set { _layoutTemplate = value; }
}
[Browsable(false)]
[DefaultValue(null)]
[TemplateContainer(typeof(ItemContainer))]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate ItemTemplate {
get { return _itemTemplate; }
set { _itemTemplate = value; }
}
#endregion Public Properties
public override void DataBind() {
if ((_itemTemplate != null) && (_layoutTemplate != null)) {
if (this.phContents.HasControls())
this.phContents.Controls.Clear(); // Clear any existing child controls.
LayoutContainer parent = new LayoutContainer(this.RootClass); // Apply the RootClass only to the Root item
_layoutTemplate.InstantiateIn(parent);
PlaceHolder ph = parent.FindControl(this.LayoutPlaceholderID) as PlaceHolder;
if (ph == null)
throw new FormatException(string.Format("Unable to find the LayoutTemplate's PlaceHolder object. Either one does not exist or the name {0} specified in the LayoutPlaceholderID does not match the ID of the PlaceHolder.", this.LayoutPlaceholderID));
this.RecurseBranches(this.DataSource.ToList(), ph);
this.phContents.Controls.Add(parent);
} else {
throw new FormatException("Both the LayoutTemplate and the ItemTemplate must be defined.");
} // if the template has been defined
base.DataBind();
}
/// <summary>
/// This method will take the List of Branches and generate an unordered list with however many branches are necessary.
/// </summary>
/// <param name="Branches"></param>
/// <param name="Canvas"></param>
private void RecurseBranches(List<Branch> Branches, Control Canvas) {
foreach (Branch branch in Branches) {
ItemContainer SingleItem = new ItemContainer(branch);
_itemTemplate.InstantiateIn(SingleItem);
if (branch.HasChildren) {
LayoutContainer NewGroup = new LayoutContainer(); // Notice no RootClass being passed in here
_layoutTemplate.InstantiateIn(NewGroup);
PlaceHolder NewCanvas = NewGroup.FindControl(this.LayoutPlaceholderID) as PlaceHolder;
PlaceHolder Parent = SingleItem.FindControl(this.LayoutPlaceholderID) as PlaceHolder;
this.RecurseBranches(branch.Children.ToList(), NewCanvas); // Add new Items to the Group
Parent.Controls.Add(NewGroup); // Add the new Group to its Parent Item
} // if there are any children to go under this node
Canvas.Controls.Add(SingleItem); // Add the current Item to the Canvas
} // foreach of the Branches to bind
} // RecurseBranches - Method
} // HeirarchicalList - Class
#region Container Classes
public class LayoutContainer : Control, INamingContainer {
public string RootClass { get; set; }
internal LayoutContainer() { }
internal LayoutContainer(string RootClass) {
this.RootClass = RootClass;
} // LayoutContainer - Constructor
} // LayoutContainer - Class
public class ItemContainer : Control, INamingContainer {
public Branch BranchItem { get; set; }
internal ItemContainer(Branch BranchItem) {
this.BranchItem = BranchItem;
} // ItemContainer - Constructor
} // ItemContainer - Class
#endregion
}

Resources