ich habe einen WCF service mit wsHttpBinding und Message Security.
Bislang funktionierte alles wunderbar.
Nun rufe ich in einer Methode des Service eine exe auf:
using (var proc = new Process())
{
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = Path.Combine(exePath, "ex.exe");
proc.StartInfo.Arguments = string.Format("\"{0}\" \"{1}\"", sourceFile, destFile);
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
if (!proc.WaitForExit(10000 + (int)Math.Min(filesize / 50L, 600000L)))
{
proc.Kill();
Thread.Sleep(1000);
throw new Exception("Timeout");
}
using (var errorReader = proc.StandardError)
{
var error = errorReader.ReadToEnd();
if (!string.IsNullOrEmpty(error)) throw new Exception(error);
}
}
Das funktioniert auch wunderbar. Ich werte das Ergebnis aus liefere es zurück...
Bei dem nächsten Aufruf einer (anderen) Methode des Services bekomme ich allerdings eine FaultException mit der folgenden Fehlermeldung:
Fehler
Die Nachricht konnte nicht verarbeitet werden. Wahrscheinliche Ursache: Die Aktion "..." ist falsch ist, die Nachricht enthält ein ungültiges oder abgelaufenes Sicherheitskontexttoken oder zwischen Bindungen besteht ein Konflikt. Das Sicherheitskontexttoken wäre ungültig, wenn der Dienst den Kanal aufgrund von Inaktivität abgebrochen hätte. Erhöhen Sie das Empfangszeitlimit für die Bindung des Dienstendpunkts, um zu verhindern, dass der Dienst Leerlaufsitzungen vorzeitig abbricht.
Unter InnerException.Code.SubCode.Name steht BadContextToken.
Wenn ich den obigen Code auskommentiere läuft alles wie es soll.
Hat jemand eine Idee, wieso der (erfolgreiche) Aufruf eines externen Prozesses in einer Service Methode dafür sorgt, dass der Kanal "gefaulted" wird?
ich habe einen WCF Service mit zwei Schnittstellen.
Eine ungesicherte Basisschnittstelle mit einfachem basicHttpBinding
Und eine gesicherte Schnittstelle mit wsHttpBinding
in der app.config stehen. Das wird sich natürlich später ändern.
Wenn ich den Server auf meinem Windows-7 Rechner laufen lasse, klappt alles wunderbar. Beide Services sind erreichbar. Egal ob ich den Client auf dem selben Rechner oder auf einem anderen laufen lasse.
Wenn ich den Server allerdings auf unserem 1&1 Server (Windows 2008 R2 Server) laufen lasse, klappt nur die Verbindung zum basis Service. Auch wenn der Client ebenfalls auf diesem Server läuft.
Scheinbar wird die Anfrage bereits vom IIS geblockt, denn die Authentifizierungs-Methode des AmagnoUserNamePasswordValidator wird gar nicht erst aufgerufen.
Folgende SecurityNegotiationException bekomme ich, wenn ich eine Methode des gesicherten Service aufrufe:
Fehler
Der Aufrufer wurde vom Dienst nicht authentifiziert.
InnerException (FaultException): Die Anforderung für ein Sicherheitstoken konnte nicht erfüllt werden, weil ein Fehler bei der Authentifizierung auftrat.
InnerException StackTrace: bei System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
bei System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
StackTrace:
Server stack trace:
bei System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)
bei System.ServiceModel.Security.SspiNegotiationTokenProvider.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Security.TlsnegoTokenProvider.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
bei System.ServiceModel.Security.CommunicationObjectSecurityTokenProvider.Open(TimeSpan timeout)
bei System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
bei System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
bei System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
bei System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
bei System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
bei System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
bei System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
bei System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
bei System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
bei System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
bei System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
bei System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
bei System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
bei System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
bei Amagno.WindowsClient.AmagnoServiceReference.IAmagnoService.GetAuthenticatedUser(GetAuthenticatedUserArg arg)
bei Amagno.WindowsClient.AmagnoServiceReference.AmagnoServiceClient.GetAuthenticatedUser(GetAuthenticatedUserArg arg) in d:\Amagno\Client\AmagnoWindowsClient\Service References\AmagnoServiceReference\Reference.cs:Zeile 6849.
Ich habe auf dem Server VisualStudio installiert um debuggen zu können und die Verbindung zum basic Service klappt auch wunderbar...
Leider habe ich keine Ahnung, wo ich ansetzen soll. Ich bin kein Admin und habe auch keinen zu Verfügung.
Wo loggt der IIS die Verbindungsversuche und die Fehler? Wo kann ich da reinschauen? Was muss ich im IIS einstellen, damit die Anfrage durchkommt?
Du könntest statt der Referenz auf die bool Variable zwei Lambda Expressions übergeben, eine die die Variable setzt, eine zweite, die den Wert liefert, sofern Du beides brauchst...
ich möchte einen WCF Service erstellen mit zwei Endpunkten.
Bindings: netTcp und wsHttp
Security Mode: jeweils Message
Client Credential Type: jeweils UserName
Die Beispiele aus dem Wrox-Buch "Professionasl WCF 4" setzen für die Identität der Endpunkte X509-Zertifikate ein. Darauf möchte ich gerne verzichten. Wenn ich das richtig verstanden habe, kann man aber auf die Identität nicht verzichten, da diese für die Server Zertifizierung nötig ist. Nun gibt es die Möglichkeit für die Identität einen RSA Schlüssel, statt eines X509 Zertifikats zu verwenden. Nun mein Problem: Ich finde nirgends 'ne Anleitung, wie das geht. Kann mir da jemand weiterhelfen?
OS: Windows 7 Home Premium (x64)
Visual Studio 2010 Professional
IIS7.5 (Features siehe angehängtes Bild)
Der IIS wurde erst nach dem Visual Studio installiert.
Ich habe ein Framework 4.0 Projekt "wcf dienstanwendung" angelegt.
Kompiliert.
Dann mit dem wcf konfigurations editor die web.config bearbeitet.
- Neuen Dienst erstellt
- die dll ausgewählt ...
- HTTP
- Basic
- keine Adresse
- Endpunkt in "Basic" benannt
- Ein Binding erstellt und auch Basic benannt
Gespeichert
In den Projekteigenschaften unter WEB "Lokalen IIS-WebServer verwenden" angewählt.
Mit F5 gestartet
Nun bekomme ich statt einer Seite auf der u.a. "Metadata publishing for this service is currently disabled" stehen sollte eine Fehlerseite mit dem Fehler 403.14.
Ich habe aspnet_regiis -i für Framework64\v4.... und Framework\v4....
ausgeführt. Außerdem "ServiceModelReg -ia" für beide 4er Frameworks und "ServiceModelReg -i" in ....\v3.0\Windows Communication Foundation"
Aber wie referenziere ich die einzelnen Elemente von _BracketValues um sie zu vergleichen? Der Indexer und ElementAt sind nicht in SQL übersetzbar, sprich, mein Beispiel funktioniert nicht.
Wenn ein neuer DataValue gespeichert werden soll, rufe ich für diesen zunächst FindEqualInList() mit der Tabelle als Parameter auf um zu sehen, ob es schon einen identischen Wert gibt... Das funktioniert auch wunderbar. Leider verlasse ich in dem FindEqualInList in der Klasse Bracket den DataBase-Context in dem Moment in dem ich das ToList() aufrufe. Hier werden alle in Frage kommenden Brackets aus der DB geladen und dann wird die Liste weiter eingeschränkt. Ich mache das ToList().FindAll(), da ein Where nicht funktioniert, da die weitere Lambda-Expression nicht in SQL übersetzt werden kann.
Nun meine Frage: (Wie) kann ich die Lambda-Expression so umwandeln, dass sie in SQL übersetzbar ist? Das würde das Laden in den Speicher verhindern und sicher wesentlich schneller laufen.
[DataContract]
[Table(Name = "DataValues")]
[InheritanceMapping(Code = "BoolValue", Type = typeof(BoolValue))]
[InheritanceMapping(Code = "Bracket", Type = typeof(Bracket), IsDefault = true)]
public abstract class DataValue
{
[Column(IsPrimaryKey = true)]
public Guid Id { get; set; }
[Column(IsDiscriminator = true)]
private string Class;
public Enum Association { get { return _Association.ToEnum(); } set { _Association = value.ToFullName(); } }
[Column]
[DataMember]
private string _Association { get; set; }
[Column]
public Guid? MetadataId { get; set; }
private EntityRef<Bracket> _Metadata;
[DataMember]
[Association(ThisKey = "MetadataId", OtherKey = "Id")]
public Bracket Metadata { get { return _Metadata.Entity; } set { _Metadata.Entity = value; } }
}
[DataContract]
public class BoolValue : DataValue
{
[DataMember]
[Column(CanBeNull = true)]
public bool Bool { get; set; }
}
[DataContract]
public class Bracket : DataValue, IEnumerable<ValueAssign>
{
[Association(OtherKey = "SourceItemId")]
internal EntitySet<ValueAssign> _BracketValues = new EntitySet<ValueAssign>();
[DataMember]
private List<ValueAssign> BracketValues { get; set; }
public IEnumerator<ValueAssign> GetEnumerator()
{
return BracketValues.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return BracketValues.GetEnumerator();
}
}
[DataContract]
[Table(Name = "ValueAssigns")]
public class ValueAssign
{
[Column(IsPrimaryKey = true)]
internal Guid SourceItemId { get; set; }
[Column(IsPrimaryKey = true)]
public Guid DestinationItemId { get; internal set; }
[DataMember]
[Column(IsPrimaryKey = true)]
public int Ordinal { get; internal set; }
private EntityRef<DataValue> _DestinationItem;
[DataMember]
[Association(ThisKey = "DestinationItemId", OtherKey = "Id")]
public DataValue DestinationItem { get { return _DestinationItem.Entity; } set { _DestinationItem.Entity = value; } }
public Enum Association { get { return _Association.ToEnum(); } internal set { _Association = value.ToFullName(); } }
[DataMember]
[Column]
private string _Association { get; set; }
}
Nun zum Problem: Vorher war die Liste BracketValues in der Klasse Bracket public und es wurde überall direkt darauf zugegriffen. Bracket war nicht IEnumerable.
Jetzt wollte ich gerne im Add und anderen Methoden noch was prüfen und den Zugriff auf BracketValues nur noch indirekt zulassen. Dazu habe ich Methoden wie Add und Remove in Bracket angelegt und Bracket auch die Schnittstelle IEnumerable gegeben, da ich häufig in foreach-Schleifen über die BracketValues ging...
Nun bekomme ich aber ein Problem mit der Erzeugung der Tabellen in der Datenbank. Wenn ich mein Programm startete, wurden alle Tabellen in der DB erzeugt, wenn sie noch nicht da waren. Jetzt bekomme ich dort folgende Fehlermeldung: Das Schlüsselelement "Id" für Schlüssel "Id" im Typ "ValueAssign" konnte nicht gefunden werden. Entweder ist der Schlüssel falsch, oder der Name des Felds bzw. der Eigenschaft in "ValueAssign" wurde geändert.
Mir ist klar, das es an dem IEnumerable liegt, aber ich weiß nicht, was das Problem genau ist und wie ich es lösen kann. Ich habe mal das IEnumerable rausgenommen und dafür eine ToArray() Methode eingeführt, über die ich die foreach Schleifen nun laufen lasse. Damit funktioniert es wieder. Dennoch würde ich lieber das IEnumerable drin lassen. In meinem Linq-Buch steht dazu natürlich nichts. Auch die Beschreibung des Table-Attributes liefert nichts. Kann mir einer von Euch das Problem erklären, oder auf gute Lektüre verweisen, in der es geklärt wird?
Ich habe die Klassen hier natürlich auf das nötigste reduziert...
Ich bastele gerade mit Advanced Installer einen neuen Installer für mein Produkt. Vorher hatte ich einen selbst gebauten, der nicht Windows Installer benutzte. Nun habe ich eine Aufwendigere Custom Action in C# geschrieben, da ich weder c++ noch vbscript beherrsche. Die dll ist ComVisible und wird mit regasm registriert. Mit einem einfachen VBScript rufe ich nun die c#-Methode auf.
Nun versuche ich das selbe auf einem 64 Bit System.
Im Advanced Installer gibt es bei der Custom Action eine CheckBox "64 Bit Script"
Wenn ich dieses setzte bekomme ich einen Fehler. InstallationTool.InstallationTool kann nicht erstellt werden.
Wenn ich das Häkchen nicht setze, gibt es keinen Fehler, aber die Funktion liefert nicht das zurück was sie sollte. Sie liefert null statt des Pfades, der in der Registry steht...
Ich habe dann eben schnell zum Test in c# eine Consolen Anwendung geschrieben, die die Methode (GetOldApplicationPath()) aufruft und das Ergebnis auf der Console ausgibt. Wenn ich dieses ausführe, bekomme ich das erwünschte Ergebnis.
Wieso klappt es mit VBScript nicht? Was läuft falsch, bzw. was muss ich anders machen?
Hier eben noch der Code der GetOldApplicationPath:
public string GetOldApplicationPath()
{
string path = null;
using (RegistryKey softwareKey = Registry.LocalMachine.OpenSubKey("Software"))
if (softwareKey != null)
using (RegistryKey dpKey = softwareKey.OpenSubKey("DocuPortal.NET"))
if (dpKey != null)
using (RegistryKey verKey = dpKey.OpenSubKey("Version"))
if (verKey != null)
{
using (RegistryKey volKey = verKey.OpenSubKey("VOL8"))
if (volKey != null)
foreach (string v8Instance in volKey.GetSubKeyNames())
using (RegistryKey instKey = volKey.OpenSubKey(v8Instance))
if (instKey != null)
{
var val = instKey.GetValue("ApplicationPath");
if (val != null)
path = val.ToString();
if (Directory.Exists(path))
{
instKey.Close();
break;
}
path = null;
}
if (path == null)
using (RegistryKey volKey = verKey.OpenSubKey("VOL7"))
if (volKey != null)
foreach (string v7Instance in volKey.GetSubKeyNames())
using (RegistryKey instKey = volKey.OpenSubKey(v7Instance))
if (instKey != null)
{
var val = instKey.GetValue("ApplicationPath");
if (val == null) continue;
path = val.ToString();
if (Directory.Exists(path))
{
string dllPath = Path.Combine(Path.Combine(path, "bin"), "data.dll");
if (File.Exists(dllPath))
{
var fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(dllPath);
if (fvi.ProductBuildPart ≥ 1235) break;
}
}
path = null;
}
}
if (path != null) path = Path.GetDirectoryName(path);
return path;
}
Vielen Dank schon Mal im voraus für eventuelle Hilfe.
Gruß T-Man
Wenn klar ist, dass es nur die beiden Unterstriche gibt, kannst Du auch mit FindLast("_") die Position des letzten Unterstrichs ermitteln und mit SubString arbeiten...
Wichtig ist, dass Du weißt, wie die Namen allgemein aussehen können...
Eine Möglichkeit ist natürlich, eine weitere Spalte mit der Länge oder dem Hashcode des Wortes einzufügen und diese dann mit in den PK aufzunehmen. Bei einer schon bestehenden Tabelle ist diese Änderung allerdings nicht so trivial. Und außerdem gefällt es mir nicht eine weitere Spalte einzubauen, die ich eigentlich gar nicht benötige, nur weil ACCESS und MSSQL scheinbar nicht in der Lage sind dass von daß zu unterscheiden.
Das Datenbankdesign ist in der tat nicht das beste, aber ich kann es jetzt nicht mal eben ändern.
Es geht hier um Schlagworte, die ich in einer Tabelle speichere. Jedes sollte natürlich nur einmal vorkommen, daher der PK. Nun kann ich aber nicht mehr 'dass' eintragen, wenn schon 'daß' drin steht. Eben so nicht 'Masse', wenn schon 'Maße' drin steht, was viel schlimmer ist, da es sich hier um verschiedene Worte handelt.
Es geht nicht um Sortierung bei einem Select, sondern um das Speichern ansich (INSERT). Das funktioniert schon nicht...
Desshalb muss ich der Spalte eine andere Sortierregel geben. Und das muss ich programmatisch (z.B. per SQL) machen können, da ich nicht zu jedem Kunden rennen kann um in seiner DB die Spalte zu bearbeiten.
Und ich möchte es den Kunden auch nicht zumuten das selbst machen zu müssen.
Da meine Applikation sowohl MSSQL als auch ACCESS unterstützt benötige ich für beide DBs eine Lösung. Meine App erstellt die Tabellen und Spalten selbst. Sie sollte auch solche Regeln einstellen können...
das dynamischste ist Reflection, wie herbivore schon vorschlug. Wenn Du auf Reflection verzichten möchtest, kannst Du alternativ zur switch-Anweisung ein Dictionary benutzen:
ich habe das ss/ß Problem.
In einer Spalte, die Primary Key ist, will ich sowohl dass als auch daß eintragen können. Leider sehen Access und MSSQL die Worte als identisch an und es geht nicht. Habe schon viel gegoogelt und dabei immer wieder den Tipp gefunden, man solle die Sortierreihenfolge ändern. Z.B. auf LATIN1_GENERAL_BIN. Wie das geht habe ich nirgends gefunden.
Optimal wäre, wenn ich für eine Spalte per SQL Befehl diese Sortierreihenfolge ändern könnte.
Es wäre aber auch OK, wenn ich die Einstellung für die gesammte DB angeben müsste.
Kann mir da jemand weiterhelfen?
Ich brauche sowohl für ACCESS als auch für MSSQL eine Lösung.
Ich habe eine asp.NET Anwendung, die in der global.asax im Event-Handler BeginRequest die URL auswertet und dann entsprechend eine Seite zurückliefert.
Wenn ich sie aus dem VS starte, klappt es. Egal, ob ich main.aspx, oder fgsfdgv.dffw als url angebe, der Event-HAndler wird angesprungen uns alles funzt.
Nun muss ich den IIS (6.0) auf unserem Server so konfigurieren, dass er genau so funktioniert. Und daran beiß ich mir bislang die Zähne aus. Rufe ich die main.aspx auf, ist alles OK, aber bei hggsgh.asad bekomme ich die Standard 404 Fehlermeldung. Meine Anwendung wird nicht gestartet.