Laden...

MEF Konfigurationsystem mit XMLSerializer

Erstellt von querl vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.989 Views
Q
querl Themenstarter:in
10 Beiträge seit 2011
vor 12 Jahren
MEF Konfigurationsystem mit XMLSerializer

Hi zusammen

Bin noch in ein blutiger Anfänger und beschäftige mich im Moment mit dem Plugin System MEF und hänge an der Umsetzung eines einfachen Konfigurationssystem. Die Hauptapplikation und die Plugins sollten jeweils eigene Konfigurationsdateien haben. Primäre will ich die Einstellungen als XML speichern, möchte das System aber flexibel halten, so dass ich später auch andere Varianten implementieren könnte.

Mein vereinfachter Projektaufbau

/MyApp
/MyApp/MySettings.cs
/MyApp/Programm.cs (Erstellt neue Instanz des Module Handler, sowie laden von MySettings)

/MyAppCore
/MyAppCore/Interfaces
/MyAppCore/Interfaces/IModuleHandler.cs
/MyAppCore/Interfaces/ISettingService.cs
/MyAppCore/ModuleHandler.cs
/MyAppCore/XMLSettingService.cs

/MyAppPlugin1
/MyAppPlugin1/MyAppPlugin1Setting.cs

/MyAppPLugin2
/MyAppPlugin2/MyAppPlugin2Setting.cs

ISettingSerives.cs beinhaltet
    public interface ISettingService
    {
        ISettingService LoadSettings(string path);
        void SavesSettings();

    }	

Für die HauptApp und jedes Module habe ich eine Setting Klasse (MainApp -> MySettings.cs) die die Einstellungen beinhaltet. Lesen und schreiben der Einstellungen möchte ich via XMLSerializer umsetzen.

Und hier hänge ich schon fest. Ich müsste jetzt ja bereits den Typ der zu serialisierenden Klasse wissen?

public class XMLSettingsService : ISettingService
{
	public ??? LoadSettings(string path)
	{
		try
		{
			XmlSerializer serializer = new XmlSerializer(typeof(???));
			TextReader tr = new StreamReader(path);
			XMLSettingsService mySettings = (XMLSettingsService)serializer.Deserialize(tr); tr.Close();
			return mySettings;
		}
		catch (Exception ex)
		{ 

		}
		return null;
	}
}

Bin für jede Info dankbar
Grüsse
Pat

109 Beiträge seit 2011
vor 12 Jahren

Hallo,

ohne jetzt genau zu wissen was MEF genau ist oder tut (ich dachte mal gehört zu haben das ist ein DI-Framework... aber egal) sieht es so aus das du deinem Interface und Implementierung einen generischen Parameter verpassen mußt:

   
    public interface ISettingService<T>
    {
        T Load(string path);
        void Save(T settings);
    }

    public class SettingService<T> : ISettingService<T> where T : class
    {
        public T Load(string path)
        { ... }

        public void Save(T settings)
        { ... }
    }

Obiger Code funktioniert aber nur wenn eine generische Implementierung für alle Settings-Klassen ausreicht, also du es hinbekommst das sich (bis auf den Typ natürlich) nichts weiter unterscheidet. Falls nicht mußt du für jede Settings-Klasse eine eigene SettingService-Klasse bauen.

Schau dir mal folgenden Beitrag zu Repositories an: LINQ / DataContext / Problem beim Speichern
Da geht es um so ziemlich die selbe Sache wie du vorhast, nur das dort die Persistierung von einem OR-Mapper und bei dir über xml-Serialisierung erfolgen soll. Mal abgesehen von der Dskussion über korrekte Implementierungen usw. siehst du dort verschiedene Ansätze (bin zu faul das alles selber aufzuschreiben 😃

PS: zu dem where T : class schöner wäre es deinen Settings-Klassen ein Interface (z.B.: ISettings) zu verpassen und durch where T : ISettings die erlaubten Typen zu definieren...

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

N
135 Beiträge seit 2006
vor 12 Jahren

Ich würde es so machen:


public static object LoadSettings(string path, Type Objecttype)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(Objecttype);
                TextReader tr = new StreamReader(path);
                object mySettings = serializer.Deserialize(tr); tr.Close();
                return mySettings;
            }
            catch (Exception ex)
            {
 
            }
            return null;
        }

Der Aufruf erfolgt dann so:


 DatenClass daten = (DatenClass)LoadSettings("c:\\pfad\\tmp.xml", typeof(DatenClass));
109 Beiträge seit 2011
vor 12 Jahren

Ich würde es so machen:

Hmm oke so kann man das auch machen... bei ner kleinen Probierapplikation mit maximal 3 Klassen. Ne, nicht mal dann würde ich das so machen 😉

Sorry, aber ich finde das ist ein ganz übler Stil:

  1. du gibst einen Typ in die Methode
  2. der Rückgabewert der Methode ist object und muß
  3. deshalb beim Aufruf gecastet

Wie er schreibt möchte er sein System flexibel halten und deshalb finde ich sollte er es auf keinen Fall so machen wie du vorgeschlagen hast (nochmal sorry... aber das ist meine Meinung)

Und ich sehe auch nicht den Unterschied zu meinem Beispiel. Oke, ich habe auf die Ausprogrammierung der Load-Methode verzichtet aber die ist ja ähnlich, bis auf den Rückgabetyp, welcher bei mir halt T ist.
Wenn MEF wirklich das ist was ich vermute dann kann er sich seine Services mit dem entsprechenden Typparameter über Dependency Injection an die Klasse geben lassen und ohne weiteres Zutun auf sehr elegante Art verwenden.

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

N
135 Beiträge seit 2006
vor 12 Jahren

Anders geht es immer, aber warum kompliziert wenn es einfach geht... und das auch noch sehr flexibel.
Code sollte man Wart und wiederverwendbar machen, genau das ist die Methode.

Wenn Dir das so nicht gefällt musst Du das nicht nutzen und Deinen Weg gehen.

109 Beiträge seit 2011
vor 12 Jahren

Code sollte man Wart und wiederverwendbar machen, genau das ist die Methode.

Aja... und woran machst du das fest? Für mich treffen solche Eigenschaften auf eine Software zu bei der ich es schaffe die Testabdeckung (Stichwort Unit-Test) bei den theoretischen 100% zu haben. Genau dann habe ich die Module soweit entkoppelt um von Wiederverwendung, Austauschbarkeit, Modularisierung, Erweiterbarkeit usw. zu reden. Ohne mir jetzt genaue Gedanken darüber gemacht zu haben glaube ich wird das bei deiner Implementierung schwer.

aber warum kompliziert wenn es einfach geht...

hier mal die Verwendung meines unten angegeben Vorschlags:

public class Programm
    {
        public Programm(ISettingService<MySettings> settingService)
        {
            var settings = settingService.Load("C:\\temp\\settings.xml");
        }
    }

Typparameter sind gar nicht so schwer oder 😉 Und das alles in meinen Augen sehr elegant ohne Casten zu müssen oder inperformantes Reflection (für die Typbestimmung) zu verwenden. Achso... und hier weiß ich das ich die Testabdeckung auf 100% hochbekomme 😉

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

Q
querl Themenstarter:in
10 Beiträge seit 2011
vor 12 Jahren

Erst Mal vielen Dank fürs Feedback!

Nach einer längern Bahnfahrt ohne Internet bin ich ebenfalls auf die Lösung via, Type übergeben und Object als Rückgabewert, gekommen.

Um zu entscheiden wie sauber das ist, fehlt mir definitiv die Erfahrung und das Wissen. Es funktioniert ja soweit, aber so richtig zufrieden bin ich doch noch nicht...

Mit generischer Parameter hab ich mich noch nicht beschäftigt. Ich schaue mir das Mal genauer an, könnte eine saubere Lösung sein.

Thx und Grüsse
Pat

Q
querl Themenstarter:in
10 Beiträge seit 2011
vor 12 Jahren

@wackelkontakt

hier mal die Verwendung meines unten angegeben Vorschlags:

public class Programm  
    {  
        public Programm(ISettingService<MySettings> settingService)  
        {  
            var settings = settingService.Load("C:\\temp\\settings.xml");  
        }  
    }  

Typparameter sind gar nicht so schwer oder 😉 Und das alles in meinen Augen sehr elegant ohne Casten zu müssen oder inperformantes Reflection (für die Typbestimmung) zu verwenden. Achso... und hier weiß ich das ich die Testabdeckung auf 100% hochbekomme 😉

So richtig begriffen hab ich es noch nicht... Wie erstelle ich denn hier eine neue Instanz der Klasse?

109 Beiträge seit 2011
vor 12 Jahren

Sorry für die späte Antwort...

Man nennt das Dependency Injection. Also entweder du benutzt ein DI-Framework (wo ich immer noch der Überzeugung bin das MEF eines ist... deshalb habe ich das Beispiel gleich so verwendet 😃 oder du erzeugst die Instanz direkt an der Stelle wo du sie benötigst:


    var settingService = new SettingService<MySettings>();
    var settings = settingService.Load("C:\\temp\\settings.xml");

Dann kannst du dir das Interface aber eigentlich sparen.

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....