I'm trying to write a benchmark that compares JSON serialisation to Protobuf serialisation speed for a demo I'm doing tomorrow.
using System.Text;
using System.Text.Json;
using AutoFixture;
using BenchmarkDotNet.Attributes;
using ProtobufDemo.ProtoModels;
using Google.Protobuf;
namespace Benchmark;
public class JsonVsProtoBenchmark
{
private readonly AddressBook _addressBook;
public JsonVsProtoBenchmark()
{
Fixture fixture = new();
_addressBook = fixture.Create<AddressBook>();
}
[Benchmark]
public void SerialiseToJsonOnly() => JsonSerializer.Serialize(_addressBook);
[Benchmark]
public void SerialiseToJsonEncodeAndWrite() // This is more representative of what the protobuf serialiser is actually doing
{
string json = JsonSerializer.Serialize(_addressBook);
byte[] encodedBytes = Encoding.UTF8.GetBytes(json);
Stream.Null.Write(encodedBytes);
Stream.Null.Flush();
}
[Benchmark]
public void SerialiseToProtobufAndWrite() => _addressBook.WriteTo(Stream.Null); // Note we have an extra write here that's not necessarily fair
}
However, this is far from a fair test as IMessage.WriteTo(Stream) does far more than just the serialisation. Even the first layer down does loads:
public static void WriteTo(this IMessage message, Stream output)
{
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(output, "output");
CodedOutputStream codedOutput = new CodedOutputStream(output);
message.WriteTo(codedOutput);
codedOutput.Flush();
}
I've tried to compensate for some of this with my SerialiseToJsonEncodeAndWrite() test, but even then, it's not really an apples to apples comparison.
Is there any way I can just perform the serialisation step rather than going through .WriteTo().
It turns out that I can avoid using the extension method that accepts a Stream and instead use the .WriteTo(CodedOutputStream) method directly, which removes almost all of this overhead. If I pre-create this in my benchmark setup along with an instance of the NullStream I get much more representative tests.
public class JsonVsProtoBenchmark
{
private AddressBook _addressBook = null!;
private CodedOutputStream _codedOutputStream = null!;
private Stream _nullStream = null!;
[GlobalSetup]
public void Setup()
{
Fixture fixture = new();
_addressBook = fixture.Create<AddressBook>();
_codedOutputStream = new(Stream.Null);
_nullStream = Stream.Null;
}
[Benchmark]
public void SerialiseToSystemTextJsonOnly() => JsonSerializer.Serialize(_addressBook);
[Benchmark]
public void SerialiseToJsonEncodeAndWrite() // This is more representative of what the protobuf serialiser is actually doing
{
string json = JsonSerializer.Serialize(_addressBook);
byte[] encodedBytes = Encoding.UTF8.GetBytes(json);
_nullStream.Write(encodedBytes);
_nullStream.Flush();
}
[Benchmark]
public void SerialiseToProtobufAndWrite() => _addressBook.WriteTo(_codedOutputStream); // Note we have an extra write here that's not necessarily fair
}
There are clearly still some issues with this, but it seems far closer than when using the extension method.
Related
As a caveat I'm a novice with Rx (2 weeks) and have been experimenting with using Rx, RxUI and Roland Pheasant's DynamicData.
I have a service that initially loads data from local persistence and then, upon some user (or system) instruction will contact the server (TriggerServer in the example) to get additional or replacement data. The solution I've come up with uses a Subject and I've come across many a site discussing the pros/cons of using them. Although I understand the basics of hot/cold it's all based on reading rather than real world.
So, using the below as a simplified version, is this 'right' way of going about this problem or is there something I haven't properly understood somewhere?
NB: I'm not sure how important it is, but the actual code is taken from a Xamarin.Forms app, that uses RxUI, the user input being a ReactiveCommand.
Example:
using DynamicData;
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
public class MyService : IDisposable
{
private CompositeDisposable _cleanup;
private Subject<Unit> _serverSubject = new Subject<Unit>();
public MyService()
{
var data = Initialise().Publish();
AllData = data.AsObservableCache();
_cleanup = new CompositeDisposable(AllData, data.Connect());
}
public IObservableCache<MyData, Guid> AllData { get; }
public void TriggerServer()
{
// This is what I'm not sure about...
_serverSubject.OnNext(Unit.Default);
}
private IObservable<IChangeSet<MyData, Guid>> Initialise()
{
return ObservableChangeSet.Create<MyData, Guid>(async cache =>
{
// inital load - is this okay?
cache.AddOrUpdate(await LoadLocalData());
// is this a valid way of doing this?
var sync = _serverSubject.Select(_ => GetDataFromServer())
.Subscribe(async task =>
{
var data = await task.ConfigureAwait(false);
cache.AddOrUpdate(data);
});
return new CompositeDisposable(sync);
}, d=> d.Id);
}
private IObservable<MyData> LoadLocalData()
{
return Observable.Timer(TimeSpan.FromSeconds(3)).Select(_ => new MyData("localdata"));
}
private async Task<MyData> GetDataFromServer()
{
await Task.Delay(2000).ConfigureAwait(true);
return new MyData("serverdata");
}
public void Dispose()
{
_cleanup?.Dispose();
}
}
public class MyData
{
public MyData(string value)
{
Value = value;
}
public Guid Id { get; } = Guid.NewGuid();
public string Value { get; set; }
}
And a simple Console app to run:
public static class TestProgram
{
public static void Main()
{
var service = new MyService();
service.AllData.Connect()
.Bind(out var myData)
.Subscribe(_=> Console.WriteLine("data in"), ()=> Console.WriteLine("COMPLETE"));
while (Continue())
{
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine($"Triggering Server Call, current data is: {string.Join(", ", myData.Select(x=> x.Value))}");
service.TriggerServer();
}
}
private static bool Continue()
{
Console.WriteLine("Press any key to call server, x to exit");
var key = Console.ReadKey();
return key.Key != ConsoleKey.X;
}
}
Looks very good for first try with Rx
I would suggest few changes:
1) Remove the Initialize() call from the constructor and make it a public method - helps a lot with unit tests and now you can await it if you need to
public static void Main()
{
var service = new MyService();
service.Initialize();
2) Add Throttle to you trigger - this fixes parallel calls to the server returning the same results
3) Don't do anything that can throw in Subscribe, use Do instead:
var sync = _serverSubject
.Throttle(Timespan.FromSeconds(0.5), RxApp.TaskPoolScheduler) // you can pass a scheduler via arguments, or use TestScheduler in unit tests to make time pass faster
.Do(async _ =>
{
var data = await GetDataFromServer().ConfigureAwait(false); // I just think this is more readable, your way was also correct
cache.AddOrUpdate(data);
})
// .Retry(); // or anything alese to handle failures
.Subscribe();
I'm putting what I've come to as my solution just in case there's others that find this while they're wandering the internets.
I ended up removing the Subjects all together and chaining together several SourceCache, so when one changed it pushed into the other and so on. I've removed some code for brevity:
public class MyService : IDisposable
{
private SourceCache<MyData, Guid> _localCache = new SourceCache<MyData, Guid>(x=> x.Id);
private SourceCache<MyData, Guid> _serverCache = new SourceCache<MyData, Guid>(x=> x.Id);
public MyService()
{
var localdata = _localCache.Connect();
var serverdata = _serverCache.Connect();
var alldata = localdata.Merge(serverdata);
AllData = alldata.AsObservableCache();
}
public IObservableCache<MyData, Guid> AllData { get; }
public IObservable<Unit> TriggerLocal()
{
return LoadLocalAsync().ToObservable();
}
public IObservable<Unit> TriggerServer()
{
return LoadServerAsync().ToObservable();
}
}
EDIT: I've changed this again to remove any chaining of caches - I just manage the one cache internally. Lesson is not to post too early.
I have like below.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Syncfusion.Gitlab
{
public class Branches
{
public void CreateBranch(List<string> projectName, string sourceBranch, string destinationBranch)
{
}
public void CreateTag(List<string> projectName, string sourceBranch,string tagname)
{
}
public static List<string> GetBranchList(string projectId)
{
}
public static List<ProjectData> GetProjectList()
{
}
}
public class ExcelOperation
{
public void GenerateExcel(List<ProjectDetails> finalExcelData, List<string>projectUrl,List<string>tagsorBranchUrl)
{
}
}
}
I can able to test the method and got the positive output. But I do not know how to test these two method public static List<string> GetBranchList(string projectId), public static List<ProjectData> GetProjectList()
My sample test code is below. Below method is successfully passed in NUnit test.
[TestMethod]
public void CreateTags()
{
List<string> project = new List<string>();
project.Add("test1");
string sourceBranch = "master";
string tagsName = "v1.0.0";
branch.CreateTag(project, sourceBranch, tagsName);
}
How can I test the that two methods?
Update:
I can get the answer with the help of first answer. But Now I have anouther doubt.
How could I test for wrong input? I mean I know that the input I was given Is wrong but I need the green tick mark for that testing. That means the input given is wrong so the output also wrong therfore the testing is right.
In my below image. I need public void GetBranchListforWrongInput() also green tick mark.
How could I do it?
Unit testing static method is pretty much as same as testing non-static methods. It might get complex based on what logic you have in the static method.
But simplest way for your case would be as following.
[TestMethod]
public void TestGetBranchList()
{
string projectId = "someProjectId";
var result = Branches.GetBranchList(projectId);
//Assert if result has expected result.
}
[TestMethod]
public void TestGetProjectList()
{
var result = Branches.GetProjectList();
//Assert if result has expected result.
}
[TestMethod]
public void TestCreateBranch()
{
//Prepare TestData
List<string> projectName = new List<string> {"someProject"};
string sourceBranch = "sourceBranch"
string destinationBranch = "destBranch";
Branches branchesObj = new Branches();
// Call method by passing the test data.
branchesObj.CreateBranch(projectName, sourceBranch, destinationBranch);
}
This should help you resolve your issue.
I have the following class
public interface IAuthProvider
{
string GenerateKey();
}
public class AuthProvider : IAuthProvider
{
public string GenerateKey()
{
using (var rng = new RNGCryptoServiceProvider())
{
var data = new byte[16];
rng.GetBytes(data);
return BitConverter.ToString(data).Replace("-","");
}
}
}
I also have the follow unit tests to go with it
[TestClass]
public class AuthProviderTests
{
private AuthProvider _provider;
private string _key;
[TestInitialize]
public void Initialize()
{
_provider = new AuthProvider();
_key = _provider.GenerateKey();
}
[TestMethod]
public void GenerateKey_key_length_is_32_characters()
{
Assert.AreEqual(32, _key.Length);
}
[TestMethod]
public void GenerateKey_key_is_valid_uppercase_hexidecimal_string()
{
Assert.IsTrue(_key.All(c =>
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F')
));
}
[TestMethod]
public void GenerateKey_keys_are_random()
{
var keys = new List<string>
{
_provider.GenerateKey(),
_provider.GenerateKey(),
_provider.GenerateKey(),
_provider.GenerateKey(),
_provider.GenerateKey()
};
var distinctCount = keys.Distinct().Count();
Assert.AreEqual(5, distinctCount);
}
}
Everything works great. However I need to create a method (and tests to go with it) called GenerateSecret. This method will do exactly the same as GenerateKey().
Now I am thinking I should create a method called GenerateRandomHexString(int bytes) and copy the code from GenerateKey into it. Then for GenerateKey and GenerateSecret I should use the follow code:
public interface IAuthProvider
{
string GenerateKey();
string GenerateSecret();
string GenerateRandomHexString(int bytes);
}
public class AuthProvider : IAuthProvider
{
public string GenerateKey()
{
return GenerateRandomHexString(16);
}
public string GenerateSecret()
{
return GenerateRandomHexString(16);
}
public string GenerateRandomHexString(int bytes)
{
using (var rng = new RNGCryptoServiceProvider())
{
var data = new byte[bytes];
rng.GetBytes(data);
return BitConverter.ToString(data).Replace("-","");
}
}
}
Now for the tests, should I just write the tests for the GenerateRandomHexString method, or should I write tests also for the GenerateSecret and GenerateKey (which will be pretty much identical tests)
Why do need two methods that do the same thing?
Regardless, you should write separate tests.
generally unit tests should cover the public interface and not non-public members and your GenerateHexString probably shouldn't be public if it is only to be used by the other methods
your implementations are the same now, but they may diverge in the future. Without distinct test cases you may miss breaking changes introduced by someone changing one of those implementations
ultimately your tests shouldn't know or care about the internal implementation details of your code
One thing that might help in nUnit would be the TestCaseSource attribute. It would allow you to define the same test cases for both methods saving some duplication in your code.
It's a bad idea to create many interface methods to do the same thing. I also don't put overloads on interfaces. The problem this creates is that methods that have the same semantic meaning can have wildly divergent implementations. They might not in the simplest cases, but simple cases often become complex ones eventually.
I love extension methods for this problem.
public interface IAuthProvider
{
string GenerateKey();
}
public static class IAuthProviderExtensions
{
public static string GenerateSecret(this IAuthProvider provider)
{
return provider.GenerateKey();
}
}
Test:
[Test]
public void GenerateSecretIsAliasForGenerateKey()
{
var mockProvider = new Mock<IAuthProvider>();
var key = GenerateARandomStringSomehow();
mockProvider.Setup(p=>p.GenerateKey()).Returns(key);
Assert.That(mockProvider.Object.GenerateSecret(), Is.EqualTo(key));
}
I need to make all my entities serializable. So I was thinking in a BaseEntity with a Backup and a Restore method. But in the restore I can't override the object with the saved one because this is read-only.
Any solution or some other way to get the serializable entities?
My code:
internal class BaseEntity
{
private MemoryStream ms = new MemoryStream();
private BinaryFormatter bf = new BinaryFormatter();
public void Backup()
{
bf.Serialize(ms, this);
}
public void Restore()
{
this = (BaseEntity)bf.Deserialize(ms);
}
}
The more common pattern is to not make it the responsibility of your objects to serialize/deserialize themselves; rather, use an external serializer:
var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;
serializer.WriteObject(stream, yourObj);
var restoredObj = serializer.ReadObject(stream);
Edit: One way serialization can work is to use the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter (or other implementation of IFormatter). To serialize an object you pass the object and a stream. To Deserialize the object, you pass a stream (positioned at the begining of your serialized data), and it returns the serialized object and all its depenedencies.
public static class EntityBackupServices
{
public static MemoryStream Backup (BaseEntity entity)
{
var ms = new MemoryStream();
Serialize (ms, entity);
ms.Position = 0;
return ms;
}
public static void Serialize (Stream stream, BaseEntity entity)
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize (stream, entity);
}
public static BaseEntity Restore (Stream stream)
{
var binaryFormatter = new BinaryFormatter();
var entity = (BaseEntity) binaryFormatter.Deserialize (stream);
return entity;
}
}
One thing a formatter don't do (though the FormatterServices class makes it possible) is modify existing objects. So you probably don't want to have an instance method called Deserialize. You can't really do this: new LionEntity().Deserialize () where it replaces the fields of an existing instance.
Note: You'll need to put Serializable over all your types. Any fields that can't be serialized (because it's either not a struct, or it's not marked as [Serializable] will need to be marked with NonSerialized.
// A test object that needs to be serialized.
[Serializable()]
public class BaseEntity
{
public int member1;
public string member2;
public string member3;
public double member4;
// A field that is not serialized.
[NonSerialized()] public MyRuntimeType memberThatIsNotSerializable;
public TestSimpleObject()
{
member1 = 11;
member2 = "hello";
member3 = "hello";
member4 = 3.14159265;
memberThatIsNotSerializable = new Form ();
}
public MemoryStream Backup ()
{
return EntityBackupServices.Backup (this);
}
}
Edit:
The way I've mentioned is a rather standard and accepted way. If you want to venture into hackdom, you can deserialize the object the way I've mentioned, then use reflection to set each field on your existing object to the value of the deserialized object.
public class BaseEntity
{
void Restore(Stream stream)
{
object deserialized = EntityBackupServices.RestoreDeserialize(stream);//As listed above
if (deserialized.GetType () != this.GetType ())
throw new Exception();
foreach (FieldInfo fi in GetType().GetFields())
{
fi.SetValue(this, fi.GetValue (deserialized));
}
}
}
public IEntidadBase Restore()
{
return (IEntidadBase)bf.Deserialize(ms);
}
#jacklondon how would you do EntitySerializer methods?
You can do serialization process with http://www.servicestack.net/ StackService.Text module for clean entities. You don't need any attribute (serializable/datacontract) in ms way.
public class EntityFoo
{
public string Bar { get; set; }
public EntityFoo (string bar)
{
Bar = bar;
}
}
public class EntityDumper //and the EntitySerializer
{
public static string Dump<T> (T entity)
{
return new TypeSerializer<T> ().SerializeToString (entity);
}
public static T LoadBack<T> (string dump)
{
return new TypeSerializer<T> ().DeserializeFromString (dump);
}
}
public class dump_usage
{
public void start ()
{
string dump = EntityDumper.Dump (new EntityFoo ("Space"));
EntityFoo loaded = EntityDumper.LoadBack<EntityFoo> (dump);
Debug.Assert (loaded.Bar == "Space");
}
}
I don't necessarily recommend this, but here is one pattern for an object that can persist and restore its own state using serialization that creates new instances:
public sealed class MyClass
{
private Data _data = new Data();
//Properties go here (access the public fields on _data)
public void Backup()
{
//Serialize Data
}
public void Restore()
{
//Deserialize Data and set new instance
}
private sealed class Data
{
//Public fields go here (they're private externally [because Data is private], but public to MyClass.)
}
}
Note that this only works if your serializer supports non-public classes. Worst-case, you have to make the nested class public, which is ugly, but doesn't hurt encapsulation (since the instance is private).
I'm trying out Generics and I had this (not so) great idea of creating an XMLSerializer class. The code I pieced together is below:
public class Persist<T>
{
private string _path;
public Persist(string path) {
this._path = path;
}
public void save(T objectToSave)
{
XmlSerializer s = new XmlSerializer(typeof(T));
TextWriter w = new StreamWriter(this._path);
try { s.Serialize(w, objectToSave); }
catch (InvalidDataException e) { throw e; }
w.Close(); w.Dispose();
}
public T load()
{
XmlSerializer s = new XmlSerializer(typeof(T));
TextReader r = new StreamReader(this._path);
T obj;
try { obj = (T)s.Deserialize(r); }
catch (InvalidDataException e) { throw e; }
r.Close(); r.Dispose();
return obj;
}
}
Here's the problem: It works fine on Persist<List<string>> or Persist<List<int>> but not on Persist<List<userObject>> or any other custom (but serializable) objects. userObject itself is just a class with two {get;set;} properties, which I have serialized before.
I'm not sure if the problems on my Persist class (generics), XML Serialization code, or somewhere else :( Help is very much appreciated~
Edit:
code for userObject
public class userObject
{
public userObject(string id, string name)
{
this.id = id;
this.name = name;
}
public string id { get;private set; }
public string name { get;set; }
}
Looks to me like your code should just work - even though it does have a few flaws.
EDIT: Your userObject class isn't serializable. Xml serialization only works on types with a public, parameterless constructor - the current class won't work. Also, you should really rewrite your code to avoid explicit calls to .Close() or .Dispose() and instead prefer using where possible - as is, you might get random file locking if at any point during serialization an error occurs and your method terminates by exception - and thus doesn't call .Dispose().
Personally, I tend to use a just-for-serialization object hierarchy that's just a container for data stored in xml and avoids any behavior - particularly side effects. Then you can use a handly little base class that makes this simple.
What I use in my projects is the following:
public class XmlSerializableBase<T> where T : XmlSerializableBase<T>
{
static XmlSerializer serializer = new XmlSerializer(typeof(T));
public static T Deserialize(XmlReader from) { return (T)serializer.Deserialize(from); }
public void SerializeTo(Stream s) { serializer.Serialize(s, this); }
public void SerializeTo(TextWriter w) { serializer.Serialize(w, this); }
public void SerializeTo(XmlWriter xw) { serializer.Serialize(xw, this); }
}
...which caches the serializer in a static object, and simplifies usage (no generic type-paramenters needed at call-locations.
Real-life classes using it:
public class ArtistTopTracks {
public string name;
public string mbid;//always empty
public long reach;
public string url;
}
[XmlRoot("mostknowntracks")]
public class ApiArtistTopTracks : XmlSerializableBase<ApiArtistTopTracks> {
[XmlAttribute]
public string artist;
[XmlElement("track")]
public ArtistTopTracks[] track;
}
Sample serialization calls:
using (var xmlReader = XmlReader.Create([...]))
return ApiArtistTopTracks.Deserialize(xmlReader);
//[...]
ApiArtistTopTracks toptracks = [...];
toptracks.SerializeTo(Console.Out);
There can be a number of reasons why your code fails: This text is particularly helpful when having issues: Troubleshooting Common Problems with the XmlSerializer . Maybe you have some type hierarchy in your user objects and the serializer does not know about it?