I'm working on a program where i have to read several excel files to populate an instance of an object of a complex class. It has many methods and properties of different types, from double to nested lists of objects from other custom classes in the project. Is there a way to store the instance i created for future reference? I want to use that specific instance in a different project without reading all the excel files again.
For example let my class be Book.cs.
public class Book
{
public string title;
public string author;
public string publisher;
public int publishYear;
public int pages;
public LibraryRef refInfo; //another custom class with properties.
}
There's also a method that reads an excel file and sets the properties above. Then in Main i create an instance of Book class.
Book b = new Book();
b.ReadExcelFile("excelFile"); //sets the properties of the instance.
I want to be able to access the values of the properties of b from a different project, anytime i want.
You could implement a in-memory shared cache for your project during it's runtime and access the cached object if it's from another module in the same application.
Since it's a different application, there would be no shared memory. So your best bet to avoid parsing the excel file is to serialize the object into a file (in a common file location) and deserialize it back. If you are not keen on using a file system, you could also use azure blob storage.
See Binary Formatter Usage for Serialization and Deserialization.
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter(v=vs.110).aspx
Related
There is a .Net Autocad plugin in which a WCF service is used to call a method
on another process external to Autocad. Autocad entities are wrapped in custom classes and passed through WCF. Once the call returns the plug-in needs to write the result back into Autocad database.
Here is the problem: ObjectId is needed to fetch the object and write the result back; WCF serialize the data and ObjectId is not serializable. So I don't have access to the object.
Is there any workaround/solution for this?
You can use the property ObjectId.OldIdPtr which is an IntPtr (serializable). To get your ObjectId back, just do:
var id = new ObjectId(oldIdPtr);
It's a more direct way than using the handle (which need a lookup)
You have to serialize the value handle of the ObjectId since it is not serializable:
[Serializable]
public class TobeSerialized
{
private long idHandleValue;
[NonSerialized]
private ObjectId id;
public TobeSerialized()
{
this.idHandleValue = id.Handle.Value;
}
public ObjectId GetObjectId(Database database, long handleValue)
{
Handle handle = new Handle(handleValue);
ObjectId id = database.GetObjectId(false, handle, 0);
return id;
}
}
Then, when you deserialize your Class object you will be able to get the objectId by calling the method GetObjectId(Database database, long handleValue)
For each of your entity you can get handle directly without mediator (objectId).
use Entity.Handle property.
Further from autocad guide
Each object contained with in the Database object is assigned several unique ids. The unique ways you can access objects are:
Entity handle
ObjectId
Instance pointer
The most common method is to access an object by its Object Id. Object Ids work well if your projects utilize both COM interop and the managed .NET API. If you create custom AutoLISP functions, you may need to work with entity handles.
Handles are persistent between AutoCAD sessions, so they are the best way of accessing objects if you need to export drawing information to an external file which might later need to be used to update the drawing. The ObjectId of an object in a database exists only while the database is loaded into memory. Once the database is closed, the Object Ids assigned to an object no longer exist and maybe different the next time the database is opened.
I'm using C# 4.0, Asp.Net. I have a problem regarding the proper construction of a readonly structure within a custom cache I created.
Details (summary) :
My CacheManager class (singleton) uses, as parameter, an instance of the existing MemoryCache class and wraps around a few helpful methods to deal with supplementary stuff such as object life cycle within my custom cache.
That Manager deals with a simple CachableObject that takes three variables :
object
DateTime
int (duration)
In summary, my custom cache Manager stores objects for a limited amount of time in order to protect my database from frequent big queries.
Lately, I tried to :
Got back an object from the cache (ie : stored under the key -MyList)
Casted it back to a list of complexe objects
Translated the content of some properties for each complexe objects
Stored again the freshly translated list of objects within the cache, (under another key -MyTranslatedList)
The problem :
During my testing, it appeared to me that both lists stored in the cache (raw and translated one) were refering to the same underlying objects. Therefore, once translated, those objects were actually translated in both lists.
Since each list only has references to the objects, that's a perfectly normal behavior and a silly mistake from me.
The question :
As you can easily guess now, I would like to protect myself and other users of my singleton for that kind of mistakes.
I would like to insert (or store or get) any kind of object (or list of complexe objects) so they cannot be altered by anybody getting them through the cache. I would like the data within my cache to be readonly (and deeply readonly) to avoid having that kind of problem. I want anybody to have to create a deep copy (or even better, to get one) before starting to use the data stored within the cache.
What I tried so far :
I tried to make the object readonly. It didn't work as expected.
Since I'm often storing list of complexe objects, I've found the AsReadOnly method that return a IReadOnlyCollection, but while this prevents me from altering the list (add, remove) it doesn't protect the objects that are within the list.
I hope my explanation is somewhat understandable :) Is there a neat way of dealing with that kind of situation ?
I would create a class where the properties are readonly:
class ReadonlyClass
{
private string p1;
private int p2;
public ReadonlyClass(string property1, int property2)
{
p1 = property1;
p2 = property2;
}
public string Property1
{
get { return p1; }
}
public int Property2
{
get { return p2; }
}
}
If the properties are objects/other classes, you should implement a clone function that returns a copy of the object. The clone function for the above class would looke like this:
public ReadonlyClass clone()
{
return new ReadonlyClass(p1, p2);
}
Best regards
Hans Milling...
I want to share a property between two projects in the same solution, so I created a simple static class in a separate (third) project with a static property. However, when I set it in one project, the change doesn't seem to occur when I try to get the value of the property from the other project.
Since the property is static shouldn't there only be one instance of it? I've debugged and the value is indeed set after the assignment statement, why doesn't this apply when its referenced in the other project?
Here's the code:
namespace Shared
{
public static class Shared
{
public static string old { get; set; }
}
}
Assignment statement in first project
Shared.Shared.old = messageData.Items[0].DateTime;
Trying to access property in 2nd project
if (messageData.Items[0].DateTime.CompareTo(Shared.Shared.old) > 0)
A static property has one instance per process (technically, per AppDomain). If you're trying to share it between two executables, each process will get a unique value.
If you want to communicate between two executables, you'll need to use some form of Interprocess Communication, or serialize to some external source (the file system, a database, etc).
I am binding DataGrid.ItemsSource property to the List<PersonDetails> object. I am getting datas through Silverlight-enabled WCF Service. So the PersonDetails class is implemented in Web Project. Each DataGrid's header text is changing as i want if the class is located in Silverlight project. But then I can not use this class in the web service. The only solution is to add same class in to the both of the projects. But, is there any other way?
The class looks like that:
[DataContract]
public class PersonGeneralDetails
{
// Properties
[DataMember]
[DisplayAttribute(Name = "Sira")]
public int RowNumber { get; set; }
[DataMember]
[DisplayAttribute(Name = "Seriyasi")]
public string SerialNumber { get; set; }
}
It seems attributes aren't generated in web project. I know that I can change header text using DataGrid events. But i want to make it work using attributes.
The problem is the WCF DataContract is an inter-operable mechanism that can be used across languages and platforms.
If you take a look to serialized data generated by the DataContractSerializer (or its code in System.Runtime.Serialization.dll, specifically InternalWriteObjectXyz() methods) you'll see that it merely serializes values into a simple XML message. Nothing related to .NET Framework will be there so all kind of attributes, both custom and compiler generated, will be stripped out and won't even received by the client.
It works creating a copy of your data and sending them from server to client, clients will then create a new class with the same signature. Note: a NEW CLASS with the same signature, NOT JUST A NEW OBJECT of the original class.
Of course there are some workaround for this. You may write your own serializer (see this post on SO for an example) or your own ISerializationSurrogate.
If you can deploy/share your assemblies to your clients you have a nice workaround: just deploy them and DataContractSerializer will build the right object on your clients (exactly the same one you had on the server, with all its attributes). Just remember that:
If custom attributes comes from run-time values (for example because of localization) then they'll be resolved on the client, not on the server (because attributes will be created on the client, their values won't be included in the XML message).
In the client application you need to add a reference to the assembly that contains your types.
When you add your service reference you have to instruct VS to use them (or it'll create proxies), in the Service Reference Settings dialog select Reuse types in referenced assemblies (you can limit this to only assemblies you want to share).
It sounds strange but this is exactly what I want because I am using a data structure named "Project" which gets serialized to a save file. I would like to be able to de-serialize an older version of a save file with deprecated fields in tact, but then re-serialize it using only the currently used fields. The problem is that I want to get rid of those deprecated fields when re-serializing the structure in order to minimize file size. Is it possible to mark a field as "de-serializable only"?
Edit:
Thanks for the ideas! I decided to build mostly off of NickLarsen's suggestions and create an old version of the project structure with all depreciated fields in a separate namespace. The difference is that I decided to perform the upgrade upon deserialization. This is great because I can do it all in one line (hopefully you can get the gist what I'm doing here):
Project myProject = new Project((Depreciated.Project)myFormatter.Deserialize(myStream));
The constructor simply returns a new instance of the fresh minimal data structure based on the old bloated one.
Second Edit:
I decided to follow the advice of bebop instead and create new classes for each project version with the oldest version including all depreciated and new fields. Then the constructor of each project upgrades to the next version getting rid of depreciated fields along the way. Here is an illustrative example of converting from version 1.0.0 -> 1.0.5 -> current.
Project myProject = new Project(new Project105((Project100)myFormatter.Deserialize(myStream)));
One key to this is to forced the deserialized file as well as any fields into the older versions of the classes by using a SerializationBinder.
could you not create a new version of your data structure class each time the structure changes, and have the constructor for the new class take an instance of the previous class, and populate itself from there. To load the newest class you try and create the earliest class from the serialised file until one succeeds, and then pass that into the constructor of the next class in the chain repeatedly until you get the latest version of the data structure then you can save that.
Having a new class for each change in format would avoid having to change any existing code when the data structure changed, and your app could be ignorant of the fact that the save file was some older version. It would allow you to load from any previous version, not just the last one.
This sort of thing implemented by a chain of responsibility can make it easy to slot in a new format with minimal changes to your existing code.
Whilst not a textbook chain of responsibility you could implement with something like this:
(NOTE: untested code)
public interface IProductFactory<T> where T : class
{
T CreateProduct(string filename);
T DeserializeInstance(string filename);
}
public abstract class ProductFactoryBase<T> : IProductFactory<T> where T : class
{
public abstract T CreateProduct(string filename);
public T DeserializeInstance(string filename)
{
var myFormatter = new BinaryFormatter();
using (FileStream stream = File.Open(filename, FileMode.Open))
{
return myFormatter.Deserialize(stream) as T;
}
}
}
public class ProductV1Factory : ProductFactoryBase<ProductV1>
{
public override ProductV1 CreateProduct(string filename)
{
return DeserializeInstance(filename);
}
}
public class ProductV2Factory : ProductFactoryBase<ProductV2>
{
ProductV1Factory successor = new ProductV1Factory();
public override ProductV2 CreateProduct(string filename)
{
var product = DeserializeInstance(filename);
if (product==null)
{
product = new ProductV2(successor.CreateProduct(filename));
}
return product;
}
}
public class ProductV2
{
public ProductV2(ProductV1 product)
{
//construct from V1 information
}
}
public class ProductV1
{
}
this has the advantage that when you want to add ProductV3 you only need to change the class you are using in your app to be a ProductV3 type, which you need to do anyway, then you change your loading code so that it uses a ProductV3Factory, which is basically the same as a ProductV2Factory, but it uses a ProductV2Factory as the successor. You don't need to change any existing classes. you could probably refactor this a bit to get the commanality of CreateProduct into a base class, but it gets the idea across.
You have a couple options for this.
First you could create a version of your class (maybe in a different namespace) for the old format, and one for the new format. In the old class, overload the serialize function to throw an error, or convert itself to the new class and serialize that.
Second, you could just write your own serializer, which would be a bit more involved. There are plenty of resources which can help you though.
As far as I know .NET is very careful to only serialise things it can deserialise and vice versa.
I think what you are searching for is the OptionalFieldAttribute.
There isn't an attribute defined to explicitly support that but one possbility may be to define custom serialization using either ISerializable or by defining a custom serializer class for your type that takes no action when serializing