| 

.NET C# Java Javascript Exception

1
Hallo,

ich suche nach einer Möglichkeit, die Einträge für den Zugriff auf einen Webservice aus einer separaten Datei bzw. sogar aus einer DB zu Lesen.
Auf meiner Suche bin ich bisher nur auf diesen Eintrag gestoßen:
http://social.msdn.microsoft.com/forums/en-US/wcf/thread/f33e620a-e332-4fd4-ae21-88c750437355/

Gibt es keine andere Möglichkeit die Einträge aus einer Datei zu lesen?
Ich stelle mir in etwa so eine Methode vor:
public ServiceEndpoint GetEndpoint<TInterface>(string configFilename, string endpointConfigurationName)


Das man das Binding und die EndpointAddress programmatisch erzeugen kann ist mir bewusst. Ich möchte nur nicht auf die Flexibilität einer Configdatei verzichten.
Gleichzeitig darf die Konfigurationsdatei aber nicht die app.config sein.

Gruß
News:
15.12.2011
PinBack 677 8
Warum soll es denn nicht die app.config sein? Die ist genau dafür vorgesehen.
"When in Rome, do as the Romans do."
Matthias Hlawatsch 15.12.2011
Die App.config kann nach der Installation nicht mehr geändert werden ... das ist alles.
Zieht jetzt der Webservice um oder wird anders konfiguriert muss wieder ein Setup geliefert werden. Wenn ich die Konfiguration aus der DB lese reicht ein Update.
PinBack 15.12.2011
Wieso kann die app.config nicht mehr geändert werden? Wie Matthias schon sagte, ist es üblich die app.config hierfür zu verwenden. Das ist eine XML-Datei mit der Endung "config" und kann mit dem Editor bearbeitet werden.
Jürgen Luhr 15.12.2011
Auf den Rechner (Business-Umfeld) hat der Benutzer weder die Berechtigung noch die nötige Fähigkeit eine XML-Datei zu editieren. Die Softwareverteilung wäre dazu in der Lage ... macht es aber nicht. Ein neues Setup zu installieren wenn sich lediglich eine Konfiguration ändert ist auch nicht die Lösung ==> zurück zu der Frage
PinBack 15.12.2011
3 Antworten
1
Noch eine andere Idee (nach etwas MSDN-Forschung): falls Dir .NET 4 zur Verfügung steht, könnte Dir möglicherweise Loading WCF Client Configuration from Different Files with ConfigurationChannelFactory weiterhelfen.
15.12.2011
Matthias Hlawatsch 13,1k 3 9
Danke. Das sieht schon mal sehr gut aus.
Dummerweise hab ich jedoch nur .NET 3.5 zur Verfügung.
Aber das wäre ja ein Grund auf 4.0 zu wechseln.
PinBack 15.12.2011
0
OK, wiedererkennend kopfschüttelnd (nicht über Dich, sondern über das "Business-Umfeld") Deine Kommentare lesend:

Evtl. kann Dir das configSource-Attribut weiterhelfen. Siehe dazu z.B. diesen Blog. Die Idee wäre, dass Du die config-Dateien für die WCF-Dienste per Setup an einen Ort legst, an dem der Benutzer schreiben darf. Ob in dem Attribut Umgebungsvariablen verwendet werden dürfen, weiß ich leider nicht. Schlimmstenfalls müßtest Du also einen absolut adressierbaren Ort finden. Und natürlich ist die Kröte dabei, dass es 3 Dateien sind, die obendrein technisch aufgeteilt sind und nicht nach Diensten. Aber dafür bekommst Du die Konfiguration gratis und mußt kein eigenes Dateiformat definieren und parsen. WCF "einfach" zu sagen, dass es eine andere Config-Datei nehmen soll, geht meines Wissen leider nicht [Update: seit .NET 4 möglicherweise doch, siehe meine zweite Antwort].

Dem Benutzer explizit im Zuge des Setups Schreibrechte nur für die app.config zu gewähren macht der Betrieb nicht mit, oder? Er muss die Datei ja nicht selbst editieren - wie von Dir angedeutet könnte das ein Skript oder Deine Anwendung machen, solange sie das mit den Benutzerrechten darf.
15.12.2011
Matthias Hlawatsch 13,1k 3 9
Wie du schon bemerkt hast, ist das keine Anforderung die ich mir mal gerade ausgedacht habe.
Den Blog Eintrag hab ich auch schon gesehen. Könnte ich eventuell auch so machen. Schreibrechte auf die lokale App.config kann ich vergessen.
Es sollte doch aber möglich sein eine beliebige XML-Datei für die Konfiguration eines Service zu verwenden.
Sooo abwegig ist die Anforderung ja wohl nicht.
Bin gerade dabei mir die Framework-Klassen anzuschauen. Wobei die Auswertung wohl in einer internen Klasse gemacht wird … mal schauen vielleicht hilft Reflection.
PinBack 15.12.2011
0
Hab jetzt anhand der Framework-Klasse und dem Beispiel unter:
http://social.msdn.microsoft.com/forums/en-US/wcf/thread/f33e620a-e332-4fd4-ae21-88c750437355/ eine eigene kleine Klasse geschrieben.
Hier wird mit Reflection gearbeitet ... also eigentlich nicht das was man gerne macht.

Für mich scheint das Ganze aber auf den ersten Blick zu funktionieren.
Ich erstelle also eine temp. Datei anhand eines DB Eintrags und gebe diese Datei als Konfiguration mit.
var loChannelFactory = new ChannelFactory<IMyInterface>(
ServiceModelHelper.GetEndpoint<IMyInterface>(lsTempfile));

Die Hilfsklasse sieht so aus:
public static class ServiceModelHelper
{
public static ServiceEndpoint GetEndpoint<TContract>(string psConfigFilename)
{
ExeConfigurationFileMap loFileMap = new ExeConfigurationFileMap()
{
ExeConfigFilename = psConfigFilename
};
Configuration loConfiguration = ConfigurationManager.OpenMappedExeConfiguration(loFileMap, ConfigurationUserLevel.None);
var loServiceGroup = ServiceModelSectionGroup.GetSectionGroup(loConfiguration);
ServiceEndpoint loServiceEndpoint = null;

foreach (ChannelEndpointElement loEndpointElement in loServiceGroup.Client.Endpoints)
{
if (loEndpointElement.Contract == typeof(TContract).FullName)
{
loServiceEndpoint = new ServiceEndpoint(
ContractDescription.GetContract(typeof(TContract)),
CreateBinding(loServiceGroup, loEndpointElement),
CreateEndPointAdress(loEndpointElement));

if (loServiceEndpoint.Behaviors.Count == 0 && !String.IsNullOrEmpty(loEndpointElement.BehaviorConfiguration))
{
LoadBehaviors(loServiceGroup, loEndpointElement.BehaviorConfiguration, loServiceEndpoint);
}
break;
}
}

return loServiceEndpoint;
}

private static Binding CreateBinding(ServiceModelSectionGroup poServiceGroup, ChannelEndpointElement poEndpointElement)
{
BindingCollectionElement loBindingCollection = poServiceGroup.Bindings[poEndpointElement.Binding];
IBindingConfigurationElement loBindingConfiguration =
loBindingCollection.ConfiguredBindings.First
(item => item.Name == poEndpointElement.BindingConfiguration);
Binding loBinding = CreateBinding(loBindingConfiguration);

loBindingConfiguration.ApplyConfiguration(loBinding);
return loBinding;
}

private static Binding CreateBinding(IBindingConfigurationElement poBindingConfiguration)
{
const string InvokeProperty = "BindingElementType";

Type loType = poBindingConfiguration.GetType();
var loProperty = loType.GetProperties(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).First
(item => item.Name == InvokeProperty);
Type loCreateType = loProperty.GetValue(poBindingConfiguration, null) as Type;

return Activator.CreateInstance(loCreateType) as Binding;
}

private static EndpointAddress CreateEndPointAdress(ChannelEndpointElement poEndpointElement)
{
return new EndpointAddress(poEndpointElement.Address, CreateEndpointIdentity(poEndpointElement.Identity), poEndpointElement.Headers.Headers);
}

private static EndpointIdentity CreateEndpointIdentity(IdentityElement poIdentityElement)
{
const string InvokeClass = "System.ServiceModel.Description.ConfigLoader";
const string InvokeMethode = "LoadIdentity";

EndpointIdentity loEndpointIdentity = null;
if (poIdentityElement != null)
{
Type loType = typeof(ServiceEndpoint).Assembly.
GetType(InvokeClass);
loEndpointIdentity = loType.InvokeMember(
InvokeMethode,
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Static,
null,
null,
new object[] { poIdentityElement }) as EndpointIdentity;
}
return loEndpointIdentity;
}

/// <summary>
/// Siehe: http://social.msdn.microsoft.com/forums/en-US/wcf/thread/f33e620a-e332-4fd4-ae21-88c750437355/
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Type.InvokeMember", Justification = "This is a real hack, but there is no other way of doing it :(")]
private static void LoadBehaviors(ServiceModelSectionGroup group, string behaviorConfiguration, ServiceEndpoint serviceEndpoint)
{
EndpointBehaviorElement behaviorElement = group.Behaviors.EndpointBehaviors[behaviorConfiguration];
for (int i = 0; i < behaviorElement.Count; i++)
{
BehaviorExtensionElement behaviorExtension = behaviorElement[i];
object extension = behaviorExtension.GetType().InvokeMember
(
"CreateBehavior",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null,
behaviorExtension,
null,
CultureInfo.InvariantCulture
);
if (extension != null)
{
serviceEndpoint.Behaviors.Add((IEndpointBehavior)extension);
}
}
}
}
16.12.2011
PinBack 677 8

Stelle deine .net-Frage jetzt!