How to provide a plugin with data capabilities? - c#

I have an application in which i want to provide the people who write plugins to it (plugins are made by implementing a basic interface, then i load the .dll). I want to give them the possibility to create settings and save data in my existing database. I would like to do this without having to create a table for each plugin - but if its required im willing to do it. I have come up with two basic scenarios:
Give the plugin an interface, where it can get a Dictionary and serialize it to xml and save it in my database.
The plugin must be contained within a .zip file with a manifest file (my own invention) where it has a create sql script and a drop script for tables.
The first has limitations towards complex data types. The second has a larger complexity in the plugin, since it needs to be within a .zip file and unpacked etc...
Please advice on either of these approaces, or alternatives.
Cheers

Your plugin constructor should recieve SettingRepository object, which provide methods for storing the setting and save them back
public MyCustomPlugin(PluginId id, SettingsRepostiory settingsRepository)
{
_id = id;
_settingsRepository = settings;
}
public void SomePluginMethod()
{
PluginSettings setting = settingsRepository.Settings.WithId(_id);
//...
}
where PluginSettings indeed could be a dictionary, that serialized to XML

I am a little hesitant toward option 2, as you are giving a third party access to essentially write SQL directly against your database. However, option 1 seems feasible and safe. As #Euphoric said, you can use multiple keys if you need to do more complicated things.

1st aproach seems fine. If application wants to save complex configuration, it can either save it as multiple keys or serialize some complex configuration object into string.

It depends how complex the plugins are.
First approach is perfect if the pugins need only settings. In this situation I don't see any limitation of the first method.
The second method does not brig anything new. You can get the same info that is in the manifest file in a datastructure and retrieve it from the plugin interface method. This is easyer because you manage only the dll file. Also if the file is very complex you can put it in a resource in the dll.
In your database you can save in a table something like: plugin_name_settingname, value into a settings table that you use for all plugins.
I once had to suport a plugin mechanism where plugins nedded their own tables.
In this case you can retrieve the new tabels schema and names in the interface method that plugin implenet. Then you need to create that in the database. Is like an insall for the plugin.

Related

C# how to store parsed data inside application?

This is rather general question, but it relates to overall application design. I'm trying to create application that follows class design standards and I'm struggling with one aspect that is how to store information internally.
For example I can create a class for a Movie with couple fields:
title
year
director
So when I parse xml files that holds this metadata I would load them into a public List. I'm not sure if this is a right approach? Since List is an instance of an object, maybe it does not belong in a class that defines Movie?
It is public list it would be available in other parts of application.
I do not see any point of parsing xml files multiple times during application activity. The same goes for accessing database like SQLite.
I looked at Singleton design and I'm not sure if that is a right approach? Plus based on Singleton samples I viewed, I do not know if I can define fields that I mentioned before.
So, my question is. How do you deal with metadata or file paths from scanned folder? Where do you keep this information inside your application?
Thank you
The class which parses the XML file shouldn't store the result. If that class parses a list of movies, it should just return an IEnumerable<Movie>, and then the caller of that class can store the result wherever it wants to.
This is a pretty general question and there are a number of ways to do it depending on your NFRs. The following is a pretty basic way that should be forward compatible with a number of approaches.
Declare the list within main program scope as an IList<Movie>.
Write a class that implements IList (e.g. class MovieList:IList<Movie>) that exposes the data you need. It can cache it if you want. It doesn't have to. For now, write the simplest code that could work.
Later, in the main program, you can change the declaration of your IList to use an IoC container to instantiate the IList (e.g. _myList = Container.Resolve<IList<Movie>>. That way you can substitute different data providers, or substitute a mock provider for unit testing.
Later, you can change the implementation of MovieList to include caching, or store the data in a DB, or whatever you want. Or you can totally rewrite it in a new class and change the configuration of your IoC container to point at the new class. You will have all sorts of options. (The decision to cache or not to cache will ultimately depend on NFRs such as storage capacity, performance, and concurrency/ACID)
The point is to write down the bones of what your program truly needs, and worry about the details of where and when to store stuff later.
I don't think it is a good idea to simply store the whole list in a global variable without some kind of abstractification.

Settings specific to a class

I have a class where I retrieve certain settings from a database (usernames and passwords). This database is sitting on a network, and it means that if the passwords are changed, I can simply change it in the database, and all the applications that use this class will still work.
I am fully aware of the pros and cons of storing usernames and passwords in a database and in a separate location. I don't want to discuss those, please.
The class has a hard-coded static string that is the path to the database. It is a fully qualified network name (not just the drive letter). I did this because we had an issue where our network DNS got screwed up, and drive letter mappings stopped working, and some people have different drive mappings anyway.
We recently had our server moved, so I now need to go through and change these hard-coded strings.
I was thinking that I should store the path in a settings / configuration file instead. I considered "application.settings", but it is not an application setting; its specific to the class. Is there a preferred way of doing this in the existing .Net framework (this is a C# issue)?
I could simply have a small text or XML file that sits in the application directory, which is probably fine... is there an existing framework namespace or open-source code snippet that someone knows of that I can use?
I think, if you want class specific configuration, you should try to have those class instances, configuration driven. Another way of thinking but; Defining a something in a configuration file, will create an instance of the defined classname.
For example: Create a section, and call it, <Modules> and create items in like: <module type="<namespace>.DBConvertor" param="username=root;passwd=whatever"> This type will be created at startup (you need some coding here). And it's even possible to create more than one instance simultaneously with it's specific configurations.
This kind of configuration is already implemented:
You might take a look at this: "How to: Create Custom Configuration Sections Using ConfigurationSection" https://msdn.microsoft.com/en-us/library/2tw134k3.aspx
And creating instances from typenames, use the Activator class.
Besides that, there are many module/plugin libraries, (like Managed Extensibility Framework (MEF) https://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx but could be a little over the top in this case).

Adding similar Web Services to .NET C# application

I'm new in web services and I'm developing a C# WCF service that is calling an external service from another company to get some client data (for example: name, address, phone, etc), this part is working fine so far.
The external service is based on a standard XML Schema, and other companies will have soon the same service generated from the same XML Schema, using the same name methods and returning the same type of xml file.
My first question is that after I complete this first implementation, there is any way to add “dynamically” the other external companies services, having the information of their URL/Ports/etc, or do I have to insert each on them manually as services reference in my internal service project every time I need to add a new one, then compile and re-deploy?
My second question is related with the data contract /members, my understanding is that even if they are returning the same XML files, their data contracts/members will be different, is that true? So I’ll have to make a specific code to read the information I need from their data contracts for each new external company?? If this is true I have been thinking to make a generic code to read the raw xml, is this the best choice?
While C# is a compiled language it does support pluggin architecture through MEF. You could use this and add a small plugin .dll for each of your sources.
That being said it's quite possible that all you need is a configuration list containing connection details for each of your sources and connecting to them dynamically. That will only work if they're using the exact same schema, so that the objects they serve will serialize the same for all sources. You will have to instantiate the proxy dynamically through code using that configuration then, of course.
I should add something for your second question. As long as you're the one defining the contract, it doesn't matter if their actual objects are different. All you care about on your end is the xml they serve, and that you can connect using your representation. In fact, you can generate the contract as a .wsdl document. Each of the service-implementer can then generate domain objects from that. On the other hand if you're not the one "owning" the contract, some of the sources may decide to do it slightly differently, which will cause you a headache. Hopefully that's not your scenario though.
Best of luck! :)
My first question is that after I complete this first implementation, there is any way to add “dynamically” the other external companies services, having the information of their URL/Ports/etc
Unfortunately yes, you will have add service, compile it and deploy every time
My second question is related with the data contract /members, my understanding is that even if they are returning the same XML files, their data contracts/members will be different, is that true?
If you will use auto generated every service will create different contracts. I would think about creating you own class and convert external classes using reflection and extension methods

Save and restore type (not object) created at runtime?

Inside our application (C# - .NET 4.5) we have a report generation tool. This tool must receive only the SQL command, verify it and from that, create a whole new report with available fields with the same name as specified by the SQL command and corresponding data types, similar to what an ORM tool would do.
Because of the nature of this tool we're using Reflection and Emit to create a whole new class. From fields provided by a dataReader (System.Data.SqlClient.SqlDataReader) we can create the type and populate it with the corresponding data.
The result of this is a IQueryable object that I can use on my reports.
This whole process is done and tested but to keep both the report, the generated class and the SQL command together we need to save this new type on the database and because or our database layout and system definitions, this requires me to provide an XML-like file or string to a method that will compress and convert to a Base64 string before saving it.
It would be a simple task if I were to save the report into a DLL file, just like shown HERE.
But since this new type must be transformed into an XML-like format I'm a little bit lost in here.
I have done the opposite on the past: fully create a type from an pure XML file, manually. I also know that I can do something similar but it would require me to loop into every detail/property/method/member/etc of the class to create the XML file.
Is there any way (like a helper from .NET framework) that could help me here?
Instead of doing it 100% manually I'd like to delegate the XML generation/parse to a tool probably with a better perforance too...
Edit:
People, READ THE TITLE BEFORE POSTING COMMENTS! I'm trying to save an XML for the type. TYPE. Not the object. The type.
#Mark Gravell
Thanks for the tip. I'll check that.
But about the schema: any way to save/load it automatically?
For saving the type, I would say either simply store the schema, and re-create a compatible type at runtime, or just use AssemblyBuilder etc and configure the dynamic-assembly as saveable, and write it as a .dll to disk (or elsewhere). Then just load the .dll at runtime and find the type. Either approach can work. If you already have the code to create a Type from a schema, the first may be easier.
For saving the data, my first instinct would be XmlSerializer, however that works via Assembly generation, so it might not like working against a fully-dynamic Type, from TypeBuilder. If XmlSerializer isn't happy, you could try protobuf-net; that also works in-memory (by default), so should be pretty happy.
However! I should note that you might also want to consider simply using a DataTable. While I don't have tons of love for DataTable, it is designed for exactly this scenario:
it can model fields that are defined only at runtime
it has inbuilt serialization of both schema and data
it implements the ComponentModel APIs for declaring runtime-models
which means most tools work with it for free

Is there any common way to save application settings in more advanced way, than plain .settings file?

There's a large WPF application with several modules, windows, self-written controls, etc.
We need to persist state for some of elements of user interface. For example:
windows layout;
controls layout;
last accepted input;
various grids' state(columns' visibility, width, order)
.Settings file seems too plain for this because of no hierarchy in it.
Why can't I just serialize some SettingsModel, containing everything I need and then restore it on application startup?
The very important requirement for persistence mechanism is that it shoud be extensible: If I refactor settings structure, and will try to de-serialize the file created with some previous version of SettingsModel class, I will obviously fail.
So the quiestion is: are there any frameworks for persisting complex settings?
As Rachel suggested, you could use XML serialization, i for one always use that for settings, it has some tolerance for changes but i do not know if it would fit all your needs.
The .Settings file supports changing the structure over time. You don't even need to use the Settings.cs file you can make your own settings providers and have them populate from the config file, each with their own customized Upgrade method to handle changes in the structure.
app.config is another common storage location. Config file settings can be accessed easily from the application and you can even build your own custom configSections
I've done this by writing my own serialization code to XML, labeling the elements to match the configuration fields. When I deserialize, I query the XML for each element I want to populate. If I'm deserializing an old version into a new config scheme that has additional elements, the XML query returns null and I instead insert a default value. It lets me handle lists of hierarchical data, I can encrypt any portion of it I need, and I don't version the XML. Although its a bit more work than using XMLSerializer, my config data doesn't change very often so it was worth it.
Since you can have lots of users, you can save each user's XML as a string in a database. System.Data.Sqlite, RaptorDb, and FileDb work well for this, as does PersistentDictionary.
Yet another alternative is to store your data in dictionaries of dictionaries and use SharpSerializer to save it as XML to either a file or one of the above databases.

Categories