Unity Json.Net: Error setting value - unity3d

I'm trying to create a convenient serialized reference to asset objects. It serialized correctly, but deserialization fails with exception
"Error setting value to 'textAssetRef' on 'TestData'."
I've prepared a small test component for Unity to illustrate this:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
public class Test : MonoBehaviour
{
public TestData testData;
public void Awake()
{
try
{
var sData = JsonConvert.SerializeObject(testData, Formatting.Indented);
UnityEngine.Debug.Log(sData);
testData = JsonConvert.DeserializeObject<TestData>(sData);
UnityEngine.Debug.Log("Done.");
}
catch (Exception x)
{
UnityEngine.Debug.LogError(x.Message);
}
}
}
[Serializable]
public class TestData
{
public TextAssetRef textAssetRef;
}
[Serializable]
[JsonConverter(typeof(Serialization))]
public class TextAssetRef : ObjectRef<TextAsset>
{
public TextAssetRef() { }
public TextAssetRef(TextAssetRef other) : base(other) { }
public TextAssetRef(TextAsset ta) : base(ta) { }
}
[Serializable]
public class ObjectRef<T> where T : UnityEngine.Object
{
public T obj;
public ObjectRef() { }
public ObjectRef(ObjectRef<T> other) { obj = other.obj; }
public ObjectRef(T obj) { this.obj = obj; }
public class Serialization : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objRef = (ObjectRef<T>)value;
var jObject = new JObject { { "path", AssetDatabase.GetAssetPath(objRef.obj) } };
serializer.Serialize(writer, jObject);
}
public override bool CanConvert(Type objectType) { return objectType == typeof(ObjectRef<T>); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var assetPath = jObject.GetValue("path").Value<string>();
return new ObjectRef<T> { obj = AssetDatabase.LoadAssetAtPath<T>(assetPath) };
}
}
}
To reproduce the error just create a new project with JSON.Net asset package in Unity, create empty object in scene, put this Test component on it and press Play.
What am I to do to get it deserialized correctly?

Related

Why am I getting "OneTimeSetUp: No suitable constructor was found..."?

I am using NUnit3 and trying to make use of TestFixtureSource in the following class hierarchy:
public class AtataTestFixtureData
{
public static IEnumerable FixtureParams
{
get
{
yield return new TestFixtureData(new AtataConfigContainer
{
AtataJsonConfig = new BaseAtataConfig()
});
}
}
}
[TestFixtureSource(typeof(AtataConfigContainer), nameof(AtataTestFixtureData.FixtureParams))]
public class AtataTestsWithDbBase : OzCsTestsWithDbBase, IAtataAbpTests
{
public AtataTestsWithDbBase()
{
}
public AtataTestsWithDbBase(AtataConfigContainer aAtataConfigContainer)
{
AtataAbpTestsAdapter = AtataAbpTestsAdapter.Instance;
AtataConfigContainer = aAtataConfigContainer;
}
}
public class SomeSiteComAuTestsBase : AtataTestsWithDbBase
{
public SomeSiteComAuTestsBase(AtataConfigContainer aAtataConfigContainer) : base(aAtataConfigContainer)
{
}
}
[TestFixture]
public class IndexTests : SomeSiteComAuTestsBase
{
/// <summary>
/// Class constructor.
/// </summary>
public IndexTests(AtataConfigContainer aAtataConfigContainer) : base(aAtataConfigContainer)
{
}
[Test]
public void Get()
{
//Arrange
//Act
IndexPageObject indexPage = Go.To<IndexPageObject>();
//Assert
}
}
When I run IndexTests.Get() I get the exception OneTimeSetUp: No suitable constructor was found but according to public IndexTests(AtataConfigContainer aAtataConfigContainer) : base(aAtataConfigContainer) I have the needed constructor.
What am I missing here?
You are getting this error because your IndexTests class has a constructor that takes parameters, but your TestFixtureSource is on a base class. The TestFixtureSource needs to be on your IndexTests. The TestFixtureSource attribute is not inherited.

NRE on Xamarin.Forms and MvvmCross Messenger Plugin

I'm trying to use the MvvmCross Messenger plugin, but I simple get it to work.. it always return a "Null Reference Exception".
Here is the BaseViewModel I created to test it:
namespace TestProject.Core.ViewModels
{
public class BaseViewModel : MvxViewModel
{
private readonly IMvxMessenger _messenger;
public BaseViewModel(IMvxMessenger messenger)
{
messenger = _messenger;
}
public IMvxCommand TestMessageCommand
{
get { return new MvxCommand(DoTestMessage); }
}
private void DoTestMessage()
{
var message = new TestMessage(this, "Potato");
_messenger.Publish(message);
}
}
}
Here is the other ViewModel that should receive the message:
namespace TestProject.Core.ViewModels
{
public class HomeViewModel : MvxViewModel
{
private string _testMessage = string.Empty;
private readonly MvxSubscriptionToken _token;
public HomeViewModel(IMvxMessenger messenger)
{
_token = messenger.Subscribe<TestMessage>(OnTestMessage);
}
private void OnTestMessage(OnTestMessage testMessage)
{
_testMessage = testMessage.Result;
}
public ICommand ShowBasePageCommand
{
get { return new MvxCommand(() => ShowViewModel<BaseViewModel>()); }
}
}
}
And finally, here is the message:
namespace TestProject.Core.Messages
{
public class TestMessage
: MvxMessage
{
public QRCodeResultMessage(object sender, string result) : base(sender)
{
Result = result;
}
public string Result { get; private set; }
}
}
I bound a button on the HomePage to the "ShowBasePageCommand", and on the BasePage there is another button bound to the "TestMessageCommand".
Full Exception:
System.NullReferenceException: Object reference not set to an nstance of an object.
at TestProject.Core.ViewModels.BaseViewModel.DoTestMessage () [0x00014] in /Users/diegopatrocinio/Projects/Xamarin/TestProject/TestProject.Core/ViewModels/BaseViewModel.cs:49
at MvvmCross.Core.ViewModels.MvxCommand.Execute (System.Object parameter) [0x00009] in <69bce0378e8e413982d3b552d7e387a8>:0
at Xamarin.Forms.Button.Xamarin.Forms.IButtonController.SendClicked () [0x0000a] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Button.cs:121
at Xamarin.Forms.Platform.Android.ButtonRenderer+ButtonClickListener.OnClick (Android.Views.View v) [0x0000f] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android\Renderers\ButtonRenderer.cs:303
at Android.Views.View+IOnClickListenerInvoker.n_OnClick_Landroid_view_View_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_v) [0x00011] in /Users/builder/data/lanes/4009/3a62f1ea/source/monodroid/src/Mono.Android/platforms/android-25/src/generated/Android.Views.View.cs:1857
at at (wrapper dynamic-method) System.Object:1b16fb3a-f768-4a9f-8e2e-60f0085ed7fb (intptr,intptr,intptr)
Stack:
System.Diagnostics.Debugger.Mono_UnhandledException_internal() in
System.Diagnostics.Debugger.Mono_UnhandledException(System.NullReferenceException ex) in /Users/builder/data/lanes/4009/3a62f1ea/source/mono/mcs/class/corlib/System.Diagnostics/Debugger.cs:122
object.1b16fb3a-f768-4a9f-8e2e-60f0085ed7fb( arg0, arg1, arg2) in
TestProject.Core.ViewModels.BaseViewModel.DoTestMessage() in /Users/diegopatrocinio/Projects/Xamarin/TestProject/TestProject.Core/ViewModels/BaseViewModel.cs:49
Please note that your constructor has inverted the parameter and the class member:
public BaseViewModel(IMvxMessenger messenger)
{
messenger = _messenger;
}
Should be
public BaseViewModel(IMvxMessenger messenger)
{
_messenger = messenger;
}

Team Foundation Server 2012 subscribe to events

In my case I need subscribe to TFS events (create/delete team project, workitem, checkin, iteration, areas) for realization some business logic. I based on this manual. Now I can catch only workitem and checkin events, but I need more (team project, iteration, areas). In this list, I did not find the right events.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.Integration.Server;
using Microsoft.TeamFoundation.VersionControl.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Server;
public class WorkItemChangedEventHandler : ISubscriber
{
public string Name
{
get { return "WorkItemChangedEventHandler"; }
}
public SubscriberPriority Priority
{
get { return SubscriberPriority.Normal; }
}
public Type[] SubscribedTypes()
{
var types = new List<Type>
{
typeof(Microsoft.TeamFoundation.WorkItemTracking.Server.WorkItemChangedEvent),// working
typeof(Microsoft.TeamFoundation.VersionControl.Server.CheckinNotification),// working
typeof(Microsoft.TeamFoundation.Integration.Server.ProjectCreatedEvent)// NOT working
};
return types.ToArray();
}
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType,
object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
statusCode = 0;
properties = null;
statusMessage = String.Empty;
try
{
EventLog.WriteEntry("WorkItemChangedEventHandler", string.Format("Entity: {0} was modified", notificationEventArgs.GetType()));
}
catch (Exception ex)
{
EventLog.WriteEntry("WorkItemChangedEventHandler", ex.Message + ex.StackTrace);
}
return EventNotificationStatus.ActionPermitted;
}
}
I have one class for CheckinNotificationEventHandler:
public class CheckinNotificationEventHandler : ISubscriber
{
public Type[] SubscribedTypes()
{
return new Type[1] { typeof(CheckinNotification) };
}
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
if (notificationType == NotificationType.Notification && notificationEventArgs is CheckinNotification)
{
...
}
return EventNotificationStatus.ActionPermitted;
}
}
and a second class for WorkItemChangedEventHandler:
public class WorkItemChangedEventHandler : ISubscriber
{
public Type[] SubscribedTypes()
{
return new Type[1] { typeof(Microsoft.TeamFoundation.WorkItemTracking.Server.WorkItemChangedEvent) };
}
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
{
...
}
return EventNotificationStatus.ActionPermitted;
}
}

resolve all given the Type

From the Autofac documentation I can see how to get all registrations for a class T:
public T[] ResolveAll<T>()
{
return _container.Resolve<IEnumerable<T>>().ToArray();
}
But when I only have the Type available, how can I get the equivalent results?
public Array ResolveAll(Type service)
{
return _container.Resolve( ???
}
I am trying to implement a wrapper class which has a pre-defined interface.
EDIT
For quick reference, the answer from Matthew Watson (with relevant ideas from David L) is:
public Array ResolveAll(Type service)
{
var typeToResolve = typeof(IEnumerable<>).MakeGenericType(service);
return _container.Resolve(typeToResolve) as Array;
}
Here is an example. I've added asserts to prove that the types returned from ResolveAll<T>(this IContainer self) are the same (and in the same order) as those returned from ResolveAll(this IContainer self, Type type):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Autofac;
using Autofac.Core;
namespace AutofacTrial
{
public abstract class Base
{
public abstract string Name { get; }
public override string ToString()
{
return Name;
}
}
public sealed class Derived1: Base
{
public override string Name
{
get
{
return "Derived1";
}
}
}
public sealed class Derived2: Base
{
public override string Name
{
get
{
return "Derived2";
}
}
}
public sealed class Derived3: Base
{
public override string Name
{
get
{
return "Derived3";
}
}
}
static class Program
{
static void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<Derived1>().As<Base>();
builder.RegisterType<Derived2>().As<Base>();
builder.RegisterType<Derived3>().As<Base>();
var container = builder.Build();
var array1 = container.ResolveAll(typeof(Base));
var array2 = container.ResolveAll<Base>();
Trace.Assert(array1.Length == 3);
Trace.Assert(array2.Length == 3);
for (int i = 0; i < array1.Length; ++i)
{
Trace.Assert(array1[i].GetType() == array2[i].GetType());
Console.WriteLine(array1[i]);
}
}
public static T[] ResolveAll<T>(this IContainer self)
{
return self.Resolve<IEnumerable<T>>().ToArray();
}
public static object[] ResolveAll(this IContainer self, Type type)
{
Type enumerableOfType = typeof(IEnumerable<>).MakeGenericType(type);
return (object[]) self.ResolveService(new TypedService(enumerableOfType));
}
}
}
The underling implementation is the same
I also used Reflector to look at the implementation of Resolve<IEnumerable<T>>(), and it winds up doing this:
public static TService Resolve<TService>(this IComponentContext context, IEnumerable<Parameter> parameters)
{
return (TService) context.Resolve(typeof(TService), parameters);
}
which calls:
public static object Resolve(this IComponentContext context, Type serviceType, IEnumerable<Parameter> parameters)
{
return context.ResolveService(new TypedService(serviceType), parameters);
}
So the two must be equivalent, since they are implemented that way.
You can invoke _container.Resolve by calling your wrapped method via reflection (MSDN), but in doing so you will lose your compile-time type safety.
public class Container
{
public T[] ResolveAll<T>()
{
return _container.Resolve<IEnumerable<T>>().ToArray();
}
public object ResolveAllGeneric(Type t)
{
MethodInfo method = GetType().GetMethod("ResolveAll")
.MakeGenericMethod(new Type[] { t });
return method.Invoke(this, new object[] { });
}
}

responding to the model's property changes in asp.net mvc2

I am having a model not in EF, but in plain text. I have to have the updated events handled for each of the model's properties so that i can log their changes.
Is there a way for this to be achieved.
Implement the INotifyPropertyChanged interface.
A simple example:
using System.ComponentModel;
public class MyModel : INotifyPropertyChanged
{
string _myProperty;
public event PropertyChangedEventHandler PropertyChanged;
public string MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
public void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
You can use it like...
public class Test
{
public static void Main()
{
var model = new MyModel();
model.PropertyChanged += new PropertyChangedEventHandler(LogChange);
model.MyProperty="apples";
model.MyProperty="oranges";
model.MyProperty="pears";
}
public static void LogChange(object sender, PropertyChangedEventArgs args)
{
Console.WriteLine(args.PropertyName + " has changed!");
Console.WriteLine("New value: "
+ sender.GetType().GetProperty(args.PropertyName)
.GetValue(sender, null));
}
}