Autocad.net Save complex Object - serialization

I'm working on a project in AutoCAD using c#, my application data is stored in complex objects
(String, double, objectId, arrays, list...) and I would like to save data for later using (serialize or saved in AutoCAD drawing) and if I re-open AutoCAD and reload my project, I can find all data in my object
Sorry for my English

So You need to use XData.
Details and sample You can find here:
https://www.keanw.com/2007/04/adding_xdata_to.html

You could serialize your class into a binary stream and then you can save it in the drawing as a bunch of binary chunks (see this topic)
But most of the time you should directly store data in Xrecords of a DBDictionary.
public abstract class RecordableObject
{
protected ObjectId dictionaryId;
protected Database database;
public string Key { get; }
protected RecordableObject(string key, Database db = null)
{
database = db ?? HostApplicationServices.WorkingDatabase;
Key = key;
using (var tr = database.TransactionManager.StartOpenCloseTransaction())
{
var NOD = (DBDictionary)tr.GetObject(database.NamedObjectsDictionaryId, OpenMode.ForRead);
DBDictionary dictionary;
if (NOD.Contains(Key))
{
dictionaryId = NOD.GetAt(Key);
}
else
{
NOD.UpgradeOpen();
dictionary = new DBDictionary();
dictionaryId = NOD.SetAt(Key, dictionary);
tr.AddNewlyCreatedDBObject(dictionary, true);
}
tr.Commit();
}
}
public abstract void SavePropertiesToDictionary();
public abstract void SetPropertiesFromDictionary();
protected void SaveData(string key, params TypedValue[] values)
{
using (var tr = database.TransactionManager.StartOpenCloseTransaction())
{
var dictionary = (DBDictionary)tr.GetObject(dictionaryId, OpenMode.ForRead);
Xrecord xrecord;
if (dictionary.Contains(key))
{
xrecord = (Xrecord)tr.GetObject(dictionary.GetAt(key), OpenMode.ForWrite);
}
else
{
xrecord = new Xrecord();
dictionary.UpgradeOpen();
dictionary.SetAt(key, xrecord);
tr.AddNewlyCreatedDBObject(xrecord, true);
}
xrecord.Data = new ResultBuffer(values);
tr.Commit();
}
}
protected T GetData<T>(string key)
{
using (var tr = database.TransactionManager.StartOpenCloseTransaction())
{
var dictionary = (DBDictionary)tr.GetObject(dictionaryId, OpenMode.ForRead);
if (dictionary.Contains(key))
{
var xrecord = (Xrecord)tr.GetObject(dictionary.GetAt(key), OpenMode.ForRead);
if (xrecord.Data != null)
return (T)xrecord.Data.AsArray()[0].Value;
}
return default;
}
}
protected T[] GetDataArray<T>(string key)
{
using(var tr = database.TransactionManager.StartOpenCloseTransaction())
{
var dictionary = (DBDictionary)tr.GetObject(dictionaryId, OpenMode.ForRead);
if (dictionary.Contains(key))
{
var xrecord = (Xrecord)tr.GetObject(dictionary.GetAt(key), OpenMode.ForRead);
if (xrecord.Data != null)
return xrecord.Data.AsArray().Select(tv => (T)tv.Value).ToArray();
}
return default;
}
}
}
Derived class example:
public class RecordableExample : RecordableObject
{
public double Size { get; set; }
public ObjectId ObjectId { get; set; }
public int[] Ints { get; set; }
public RecordableExample(string key, Database db = null) : base(key, db) { }
public override void SavePropertiesToDictionary()
{
SaveData(nameof(Size), new TypedValue((int)DxfCode.Real, Size));
SaveData(nameof(ObjectId), new TypedValue((int)DxfCode.Handle, ObjectId.Handle));
if (Ints != null)
SaveData(nameof(Ints), Ints.Select(i => new TypedValue((int)DxfCode.Int32, i)).ToArray());
}
public override void SetPropertiesFromDictionary()
{
Size = GetData<double>(nameof(Size));
Ints = GetDataArray<int>(nameof(Ints));
var handle = new Handle(Convert.ToInt64(GetData<string>(nameof(ObjectId))));
if (database.TryGetObjectId(handle, out var id))
ObjectId = id;
}
}

Related

Xamarin SQLite database creating for all tables

I have working on this topic for 4 hours but I couldn't get any solution.
My problem is actually;
I have 5 table and I wanna create one controller to create different tables.
My current codes are below but this codes create only one table.
public interface ISQLite
{
SQLiteConnection GetConnection();
}
-
public class TodoItem
{
public TodoItem ()
{
}
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public bool Done { get; set; }
}
-
public class TodoItemDatabase
{
static object locker = new object ();
SQLiteConnection database;
/// <summary>
/// Initializes a new instance of the <see cref="Tasky.DL.TaskDatabase"/> TaskDatabase.
/// if the database doesn't exist, it will create the database and all the tables.
/// </summary>
/// <param name='path'>
/// Path.
/// </param>
public TodoItemDatabase()
{
database = DependencyService.Get<ISQLite> ().GetConnection ();
// create the tables
database.CreateTable<TodoItem>();
}
public IEnumerable<TodoItem> GetItems ()
{
lock (locker) {
return (from i in database.Table<TodoItem>() select i).ToList();
}
}
public IEnumerable<TodoItem> GetItemsNotDone ()
{
lock (locker) {
return database.Query<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0");
}
}
public TodoItem GetItem (int id)
{
lock (locker) {
return database.Table<TodoItem>().FirstOrDefault(x => x.ID == id);
}
}
public int SaveItem (TodoItem item)
{
lock (locker) {
if (item.ID != 0) {
database.Update(item);
return item.ID;
} else {
return database.Insert(item);
}
}
}
public int DeleteItem(int id)
{
lock (locker) {
return database.Delete<TodoItem>(id);
}
}
}
-
public class SQLite_Android : ISQLite
{
public SQLite_Android()
{
}
#region ISQLite implementation
public SQLite.SQLiteConnection GetConnection()
{
var sqliteFilename = "TodoSQLite.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
// This is where we copy in the prepopulated database
Console.WriteLine(path);
if (!File.Exists(path))
{
var s = Forms.Context.Resources.OpenRawResource(Resource.Raw.TodoSQLite); // RESOURCE NAME ###
// create a write stream
FileStream writeStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
// write to the stream
ReadWriteStream(s, writeStream);
}
var conn = new SQLite.SQLiteConnection(path);
// Return the database connection
return conn;
}
#endregion
/// <summary>
/// helper method to get the database out of /raw/ and into the user filesystem
/// </summary>
void ReadWriteStream(Stream readStream, Stream writeStream)
{
int Length = 256;
Byte[] buffer = new Byte[Length];
int bytesRead = readStream.Read(buffer, 0, Length);
// write the required bytes
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = readStream.Read(buffer, 0, Length);
}
readStream.Close();
writeStream.Close();
}
}
--- How can I create multi tables in one controller ?
Looks like you are using Sqlite.net-pcl, right?
Multiple tables from the same model are not supported (it's for simple cases only).
You can create multiple models (possibly by just inheriting) and then call CreatTable<T> for each of them.
I solved problem. Maybe this solution helps somenone.
I have two DbHepler Class and two model class for creating two tables on DB.
Base connection codes are same;
public interface ISQLite
{
SQLiteConnection GetConnection();
}
This is the App.cs file;
public class App : Application {
public App()
{
authenticationDB = new AuthenticationDbHelper(Database);
settingsDbHelper = new SettingsDbHelper(Database);
MainPage = new Views.MainMenuPage();
}
public static CreateDB Database
{
get
{
if (database == null)
{
database = new CreateDB();
}
return database;
}
}
}
The CreateDB class is necessary for create one db for all tables
public class CreateDB
{
public SQLiteConnection database;
public object locker = new object();
public CreateDB()
{
database = DependencyService.Get<ISQLite>().GetConnection();
}
}
This interface is necessary for created tables actions. Since implement this class we can use theese methods all tables.(T is table class)(To understand look AuthenticationDBHelper class)
public interface SQLiteBase<T>
{
IEnumerable<T> GetItems();
T GetItem(long id);
long SaveItem(T item);
void UpdateItem(T item);
int DeleteItem(int id);
int Clear();
int getCount();
}
This DbHelper class will be used for delete,insert,clear.... items.
public class AuthenticationDbHelper : SQLiteBase<AuthenticationDbTable>
{
SQLiteConnection database;
object locker;
public AuthenticationDbHelper(CreateDB db)
{
database = db.database;
locker = db.locker;
database.CreateTable<AuthenticationDbTable>();
}
public int Clear()
{
lock(locker)
{
return database.DeleteAll<AuthenticationDbTable>();
}
}
public int DeleteItem(int id)
{
lock (locker)
{
return database.Delete<AuthenticationDbTable>(id);
}
}
public AuthenticationDbTable GetItem(long id)
{
lock (locker)
{
return database.Table<AuthenticationDbTable>().FirstOrDefault(x => x.UserId == id);
}
}
public IEnumerable<AuthenticationDbTable> GetItems()
{
lock (locker)
{
return (from i in database.Table<AuthenticationDbTable>() select i).ToList();
}
}
public long SaveItem(AuthenticationDbTable item)
{
lock (locker)
{
return database.Insert(item);
}
}
public void UpdateItem(AuthenticationDbTable item)
{
lock(locker)
{
database.Update(item);
}
}
public int getCount()
{
return GetItems().Count();
}
}
I know it is very confused but this is the last. We will create model for authentication.
public class AuthenticationDbTable
{
public AuthenticationDbTable(long userId, string sessionId, string username, string clientuuid)
{
this.userId = userId;
this.sessionId = sessionId;
this.username = username;
this.clientuuid = clientuuid;
}
private long userId;
private string sessionId;
private string username;
private string clientuuid;
[PrimaryKey]
public long UserId
{
get { return userId; }
set { userId = value; }
}
public string SessionId
{
get { return sessionId; }
set { sessionId = value; }
}
public string Username
{
get { return username; }
set { username = value; }
}
public string Clientuuid
{
get { return clientuuid; }
set { clientuuid = value; }
}
}
Using
AuthenticationDbTable authentication = new AuthenticationDbTable(authenticateduser.User.UserId, r.Retval.SessionStatus.SessionId, authenticateduser.User.Name, authenticateduser.Clientuuid);
App.authenticationDB.SaveItem(authentiaction);
Note
For creating second table you can use same way. You should create second DbHelper and model class. Assume that you will create a table for settings. You should create SettingsDbHelper and SettingsDbTable class. through same way.
Thank you :)

Value type field required in Razor View

I have an enum type field called Title.
[Serializable]
public enum Title
{
NotSet,
Miss = 4,
Mr = 1,
Mrs = 3,
Ms = 2
}
I want to bind a property of type Title to the Razor View but I don't want it to be a required field. However, on tabbing out or OnBlur, it is showing as required, although I have not specified this as required.
Is there any way I can get around this?
create
namespace YourApplicationName.Helper
{
public class ModelValueListProvider : IEnumerable<SelectListItem>
{
List<KeyValuePair<string, string>> innerList = new List<KeyValuePair<string, string>>();
public static readonly ModelValueListProvider TitleList = new TitleListProvider();
protected void Add(string value, string text)
{
string innerValue = null, innerText = null;
if (value != null)
innerValue = value.ToString();
if (text != null)
innerText = text.ToString();
if (innerList.Exists(kvp => kvp.Key == innerValue))
throw new ArgumentException("Value must be unique", "value");
innerList.Add(new KeyValuePair<string, string>(innerValue, innerText));
}
public IEnumerator<SelectListItem> GetEnumerator()
{
return new ModelValueListProviderEnumerator(innerList.GetEnumerator());
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private struct ModelValueListProviderEnumerator : IEnumerator<SelectListItem>
{
private IEnumerator<KeyValuePair<string, string>> innerEnumerator;
public ModelValueListProviderEnumerator(IEnumerator<KeyValuePair<string, string>> enumerator)
{
innerEnumerator = enumerator;
}
public SelectListItem Current
{
get
{
var current = innerEnumerator.Current;
return new SelectListItem { Value = current.Key, Text = current.Value };
}
}
public void Dispose()
{
try
{
innerEnumerator.Dispose();
}
catch (Exception)
{
}
}
object System.Collections.IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
return innerEnumerator.MoveNext();
}
public void Reset()
{
innerEnumerator.Reset();
}
}
private class TitleListProvider : ModelValueListProvider
{
public TitleListProvider (string defaultText = null)
{
if (!string.IsNullOrEmpty(defaultText))
Add(string.Empty, defaultText);
Add(Title.NotSet, "NotSet");
Add(Title.Miss , "Miss");
Add(Title.Mr , "Mr");
Add(Title.Mrs , "Mrs");
Add(Title.MS, "MS");
}
public void Add(Title value, string text)
{
Add(value.ToString("d"), text);
}
}
}
}
in your model
public Title? Titleformation { get; set; }
public string[] SelectedTitle { get; set; }
in your view, also add the name space to your view
#using YourApplicationName.Helper;
#Html.ListBoxFor(m => m.SelectedTitle , new SelectList(ModelValueListProvider.TitleList, "Value", "Text"))
hope this help you
Enums require values, and cannot be null (aka not set) despite what someone commented above. What I do for salutations is have a "none" member of the enum, and whenever I print this out, I just check in the code to see if the value of the enum is > 0 (aka, the none option) and don't print it.
public enum Salutation { none,
[Description("Mr.")] Mr,
[Description("Mrs.")] Mrs,
[Description("Ms.")]Ms,
[Description("Miss")] Miss }
Use a class rather than enum ie:
public class Title
{
NotSet;
Miss = 4;
Mr = 1;
Mrs = 3;
Ms = 2;
}

Custom model binder with inheritance using Web API and RavenDB

I'm developing a simple web app where I need to bind all types implementing and interface of a specific type. My interface has one single property like this
public interface IContent {
string Id { get;set; }
}
a common class using this interface would look like this
public class Article : IContent {
public string Id { get;set; }
public string Heading { get;set; }
}
to be clean here the article class is just one of many different classes implementing IContent so therefor I need a generic way of storing and updating these types.
So in my controller I have the put method like this
public void Put(string id, [System.Web.Http.ModelBinding.ModelBinder(typeof(ContentModelBinder))] IContent value)
{
// Store the updated object in ravendb
}
and the ContentBinder
public class ContentModelBinder : System.Web.Http.ModelBinding.IModelBinder {
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) {
actionContext.ControllerContext.Request.Content.ReadAsAsync<Article>().ContinueWith(task =>
{
Article model = task.Result;
bindingContext.Model = model;
});
return true;
}
}
The code above does not work because it does not seem to get hold of the Heading property even though if I use the default model binder it binds the Heading correctly.
So, in the BindModel method I guess I need to load the correct object from ravendb based on the Id and then update the complex object using some kind of default model binder or so? This is where I need some help.
Marcus, following is an example which would work fine for both Json and Xml formatter.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Runtime.Serialization;
using System.Web.Http;
using System.Web.Http.SelfHost;
namespace Service
{
class Service
{
private static HttpSelfHostServer server = null;
private static string baseAddress = string.Format("http://{0}:9095/", Environment.MachineName);
static void Main(string[] args)
{
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
try
{
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("Service listenting at: {0} ...", baseAddress);
TestWithHttpClient("application/xml");
TestWithHttpClient("application/json");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Exception Details:\n{0}", ex.ToString());
}
finally
{
if (server != null)
{
server.CloseAsync().Wait();
}
}
}
private static void TestWithHttpClient(string mediaType)
{
HttpClient client = new HttpClient();
MediaTypeFormatter formatter = null;
// NOTE: following any settings on the following formatters should match
// to the settings that the service's formatters have.
if (mediaType == "application/xml")
{
formatter = new XmlMediaTypeFormatter();
}
else if (mediaType == "application/json")
{
JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
formatter = jsonFormatter;
}
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(baseAddress + "api/students");
request.Method = HttpMethod.Get;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
HttpResponseMessage response = client.SendAsync(request).Result;
Student std = response.Content.ReadAsAsync<Student>().Result;
Console.WriteLine("GET data in '{0}' format", mediaType);
if (StudentsController.CONSTANT_STUDENT.Equals(std))
{
Console.WriteLine("both are equal");
}
client = new HttpClient();
request = new HttpRequestMessage();
request.RequestUri = new Uri(baseAddress + "api/students");
request.Method = HttpMethod.Post;
request.Content = new ObjectContent<Person>(StudentsController.CONSTANT_STUDENT, formatter);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
Student std1 = client.SendAsync(request).Result.Content.ReadAsAsync<Student>().Result;
Console.WriteLine("POST and receive data in '{0}' format", mediaType);
if (StudentsController.CONSTANT_STUDENT.Equals(std1))
{
Console.WriteLine("both are equal");
}
}
}
public class StudentsController : ApiController
{
public static readonly Student CONSTANT_STUDENT = new Student() { Id = 1, Name = "John", EnrolledCourses = new List<string>() { "maths", "physics" } };
public Person Get()
{
return CONSTANT_STUDENT;
}
// NOTE: specifying FromBody here is not required. By default complextypes are bound
// by formatters which read the body
public Person Post([FromBody] Person person)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState));
}
return person;
}
}
[DataContract]
[KnownType(typeof(Student))]
public abstract class Person : IEquatable<Person>
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
// this is ignored
public DateTime DateOfBirth { get; set; }
public bool Equals(Person other)
{
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (this.Id != other.Id)
return false;
if (this.Name != other.Name)
return false;
return true;
}
}
[DataContract]
public class Student : Person, IEquatable<Student>
{
[DataMember]
public List<string> EnrolledCourses { get; set; }
public bool Equals(Student other)
{
if (!base.Equals(other))
{
return false;
}
if (this.EnrolledCourses == null && other.EnrolledCourses == null)
{
return true;
}
if ((this.EnrolledCourses == null && other.EnrolledCourses != null) ||
(this.EnrolledCourses != null && other.EnrolledCourses == null))
return false;
if (this.EnrolledCourses.Count != other.EnrolledCourses.Count)
return false;
for (int i = 0; i < this.EnrolledCourses.Count; i++)
{
if (this.EnrolledCourses[i] != other.EnrolledCourses[i])
return false;
}
return true;
}
}
}
I used #kiran-challa solution and added TypeNameHandling on Json media type formatter's SerializerSettings.

RavenDB lazy search against Index returns uninitialized statistiscs

I am trying to run lazy queries against raven db and get the counts on total matching results. I am finding when I query against a static index, a lazy search does not initialize the statistics when the query is materialized, but otherwise it comes back all right.
Below is the test to prove this behaviour.
[TestFixture]
public class CanSearchLazily
{
private const int ServerPort = 8085;
private readonly string _serverAddress = #"http://localhost:{0}".For(ServerPort);
[Test]
public void CanGetTotalResultsFromStatisticsOnLazySearchAgainstDynamicIndex()
{
CanGetTotalResultsFromStatisticsOnLazySearchAgainstAnIndex();
}
[Test]
public void CanGetTotalResultsFromStatisticsOnLazySearchAgainstStaticIndex()
{
CanGetTotalResultsFromStatisticsOnLazySearchAgainstAnIndex("UserByFirstName");
}
private void CanGetTotalResultsFromStatisticsOnLazySearchAgainstAnIndex(string indexName = "")
{
BuilderSetup.DisablePropertyNamingFor<User, string>(x => x.Id);
var users = Builder<User>.CreateListOfSize(2000).All()
.With(x => x.FirstName = GetRandom.FirstName())
.With(x => x.LastName = GetRandom.LastName())
.Build();
using (GetNewServer())
using (var store = new DocumentStore { Url = _serverAddress }.Initialize())
{
using (var session = store.OpenSession())
{
users.ForEach(session.Store);
session.SaveChanges();
IndexCreation.CreateIndexes(typeof(UserByFirstName).Assembly, store);
session.Query<User, UserByFirstName>().Customize(x => x.WaitForNonStaleResults()).ToList();
}
using (var session = store.OpenSession())
{
var names = session.Query<User>().Select(u => u.FirstName).Distinct().Take(15).ToList();
RavenQueryStatistics stats;
var query = string.IsNullOrEmpty(indexName)
? session.Query<User>().Statistics(out stats).Where(x => x.FirstName.In(names))
: session.Query<User>(indexName).Statistics(out stats).Where(x => x.FirstName.In(names));
var results = query.Take(8).Lazily();
Assert.AreEqual(8, results.Value.ToList().Count);
Assert.AreEqual(DateTime.Now.Year, stats.IndexTimestamp.Year, "the index should have the current year on its timestamp");
Assert.IsTrue(stats.TotalResults > 0, "The stats should return total results");
}
}
}
protected RavenDbServer GetNewServer(bool initializeDocumentsByEntitiyName = true)
{
var ravenConfiguration = new RavenConfiguration
{
Port = ServerPort,
RunInMemory = true,
DataDirectory = "Data",
AnonymousUserAccessMode = AnonymousUserAccessMode.All
};
if (ravenConfiguration.RunInMemory == false)
IOExtensions.DeleteDirectory(ravenConfiguration.DataDirectory);
var ravenDbServer = new RavenDbServer(ravenConfiguration);
if (initializeDocumentsByEntitiyName)
{
using (var documentStore = new DocumentStore
{
Url = _serverAddress
}.Initialize())
{
new RavenDocumentsByEntityName().Execute(documentStore);
}
}
return ravenDbServer;
}
}
[Serializable]
public class User
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserByFirstName : AbstractIndexCreationTask<User>
{
public UserByFirstName()
{
Map = users => from user in users
select new {user.FirstName};
}
}

Serializing object graph using MongoDB Bson serializer

I've been playing a little with the MongoDB Bson serializer, using the following piece of code:
class Program
{
public class myValue
{
public int Id = 0;
public string Label = "";
}
public class myValueMap : Dictionary<string, myValue>
{
}
public class myProdData
{
public myValueMap Mapping { get; set; }
}
public class mySystemPosition
{
public string Text { get; set; }
public myProdData ProdData { get; set; }
}
static void Main(string[] args)
{
BsonClassMap.RegisterClassMap<mySystemPosition>();
BsonClassMap.RegisterClassMap<myProdData>();
BsonClassMap.RegisterClassMap<myValueMap>();
BsonClassMap.RegisterClassMap<myValue>();
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new myValueMap()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var bson = o.ToBson();
var text = Encoding.ASCII.GetString(bson);
}
}
however I don't seem to be able to get the myProdData.Mapping serialized....
Do I need to configure the MongoDB Bson serializer in a special way, to make this work?
You no need to use BsonClassMap.RegisterClassMap if you no need custom serializtion(documentation).
All your classes will be desirialzied according to default rules.
Also i am changed your example a little bit to get it work(i've replaces myValueMap class with Dictionary):
public class myProdData
{
public Dictionary<string, myValue> Mapping { get; set; }
}
static void Main(string[] args)
{
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new Dictionary<string, myValue>()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var json = o.ToJson();
Console.WriteLine(json);
Console.ReadKey();
}
Here is console output(just well formatted):
{
"Text":null,
"ProdData":{
"Mapping":{
"123":{
"_id":1,
"Label":"Item1"
},
"345":{
"_id":2,
"Label":"Item2"
}
}
}
}
You can test your serializtion using ToJson() extention method, in order to view that all correct and after that use ToBson() if need.
The problem is that myValueMap derives from Dictionary. That results in a class that the AutoMap method can't handle.
I recommend you just use the Dictionary directly, as Andrew did in his reply.
Ufortunately the myValueMap is an object that I can't easily change, however it turns out, that's pretty easy to create your own (de)serializer....
public class myValueMapSerializer : IBsonSerializer
{
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, System.Type actualType, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var res = new myValueMap();
var ser = new DictionarySerializer<string, myValue>();
var dic = (Dictionary<string, myValue>)ser.Deserialize(bsonReader, typeof(Dictionary<string, myValue>), options);
foreach (var item in dic)
{
res.Add(item.Key, item.Value);
}
return res;
}
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, IBsonSerializationOptions options)
{
throw new Exception("Not implemented");
}
public bool GetDocumentId(object document, out object id, out IIdGenerator idGenerator)
{
id = null;
idGenerator = null;
return false;
}
public void Serialize(Bson.IO.BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var ser = new DictionarySerializer<string, myValue>();
ser.Serialize(bsonWriter, typeof(DictionarySerializer<string, myValue>), value, options);
}
public void SetDocumentId(object document, object id)
{
return;
}
}