C# WCF Dienste in ASP.NET

Fou-Lu

Lt. Junior Grade
Registriert
Aug. 2006
Beiträge
290
Hallo Leute,
ich hatte da eine coole Idee für eine Anwendung wollte mal bisschen rum experimentieren.

Ich habe mir ein kleines Desktop-Tool geschrieben, das einfach nur einen WCF Service hostet.
Wenn man sich zu diesem WCF über ein anderes Tool verbindet und die Funktion im Vertrag aufruft,
dann bekommt man einfach nur einen vordefinierten String als Byte-Array zurück.

Ok soweit funktioniert es ja...

Jetzt kommt aber das besondere der Anwendung und auch ein Teil mit dem ich zuvor nichts zu tun hatte...

ASP.NET... ich hab darin eine kleine Test Website erstellt.
In der Website hab ich ebenfalls ein Textfeld (für die Adresse vom WCF Dienst in der Desktop-Anwendung) und einen Button (zum Verbinden).

So... Ich schaffs auch die Verbindung zum Desktop-Tool aufzubauen und bekomme den String auch rüber...

Wenn ich aber jetzt aus den Ajax-Controls einen Timer nehme und innerhalb des TimerTicks den String alle 2 Sek z.B. holen will, dann ist es leider so, dass er mir sagt, dass die ChannelFactory<> null ist...

Meine Frage nun... wie kann ich es so einrichten, dass der Timer ausgeführt wird, aber sich die ChannelFactory die ja den Channel zur Desktop-Anwendung erstellt sich nicht auf null setzt? Gibt es da eine Möglichkeit?

Hoffe wirklich ihr könnt mir da weiterhelfen.
 
Ok also das hier ist der Button-Klick-Ereignis:

PHP:
protected void Button1_Click(object sender, EventArgs e) {
	InitBinding();

	InitializeScreenCapture();
}


Hier die InitBinding()
in dieser Funktion wird das NetTcpBinding und die ChannelFactory konfiguriert und initialisiert.

PHP:
private void InitBinding() {
	int receiveSize = int.MaxValue;

	XmlDictionaryReaderQuotas quotas = new XmlDictionaryReaderQuotas();
	quotas.MaxArrayLength = receiveSize;

	// neues TcpBinding erstellen
	NetTcpBinding tcp = new NetTcpBinding();

	tcp.Name = "ASP WCF Test";

	tcp.ReliableSession.Enabled = true;
	tcp.ReliableSession.Ordered = true;
	tcp.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(1);

	tcp.Security.Mode = SecurityMode.None;
	tcp.Security.Message.ClientCredentialType = MessageCredentialType.None;

	tcp.TransferMode = TransferMode.Buffered;
	tcp.HostNameComparisonMode = HostNameComparisonMode.WeakWildcard;

	tcp.TransactionFlow = true;
	tcp.TransactionProtocol = TransactionProtocol.OleTransactions;

	tcp.MaxConnections = 1;
	tcp.ListenBacklog = 1;

	tcp.MaxReceivedMessageSize = receiveSize;

	tcp.ReaderQuotas = quotas;

	tcp.SendTimeout = TimeSpan.FromSeconds(3);
	tcp.ReceiveTimeout = TimeSpan.FromSeconds(3);
	tcp.CloseTimeout = TimeSpan.FromSeconds(3);
	tcp.OpenTimeout = TimeSpan.FromSeconds(3);

	try {
		EndpointAddress endpoint = new EndpointAddress("net.tcp://" + txtIP.Text + ":1777/test");
		MyChanFactory = new ChannelFactory<ICaptureService>(tcp, endpoint);
	} catch (Exception ex) {
		lblException.Text = ex.Message;
			
		try {
			if(MyChanFactory != null)
				MyChanFactory.Close();
		} catch {
			if(MyChanFactory != null)
				MyChanFactory.Abort();
		}
	}
}


Nun die InitThread Methode.
Hier wird der Channel dann geöffnet/erstellt und der Timer gestartet

PHP:
private void InitializeScreenCapture() {
	//erstellt einen neuen Channel für den Empfang der Daten.
	channel_Data = MyChanFactory.CreateChannel();

	Thread.Sleep(250);

	dataThread.Enabled = true;
}

So... bis hier her funktioniert auch alles wunderbar.
Auch wenn ich die ASP.NET Website im Debugmodus starte und die ChannelFactory oder die "channel_Data" prüfe, dann entspricht es auch nicht NULL. An dieser stelle wenn ich die Funktion "channel_Data.GetString()" aufrufe, dann bekomme ich auch den String empfangen.

Kompliziert wird es jetzt innerhalb des Timers... da wird nämlich "channel_Data" und "MyChanFactory" auf NULL gesetzt... ich habe da die Vermutung, dass der Timer evtl. die Seite neulädt und die vorher initialisierten Daten deswegen verloren gehen... aber auch wenn ich das UpdatePanel benutze passiert das selbe... :(


Hier noch der Code des Timers:

PHP:
protected void dataThread_Tick(object sender, EventArgs e) {
	try {
		byte[] receivedBytes = channel_Data.GetString();

		if (receivedBytes != null) {
			string str = System.Text.Encoding.ASCII.GetString(receivedBytes);
			lblHelloWorld.Text = str;
		}
	} catch (ThreadAbortException) {
		dataThread.Enabled = false;

		try {
			if(MyChanFactory != null)
				MyChanFactory.Close();
		} catch {
			if(MyChanFactory != null)
				MyChanFactory.Abort();
		}
	} catch (Exception ex) {
		lblException.Text = ex.Message;

		dataThread.Enabled = false;

		try {
			if(MyChanFactory != null)
				MyChanFactory.Close();
		} catch {
			if(MyChanFactory != null)
				MyChanFactory.Abort();
		}
	}
}


Ich poste sicherheitshalber noch einen kleinen Ausschnitt aus der Website wie es bislang aufgebaut ist...

HTML:
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
	<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>

	<table class="style4">
		<tr>
			<td width="100">
				<asp:Label ID="Label1" runat="server" Text="IP-Adresse:"></asp:Label>	
			</td>
			<td>
				<asp:TextBox ID="txtIP" runat="server" Width="150px"></asp:TextBox>
			</td>
		</tr>
		<tr>
			<td colspan="2">
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<asp:Label ID="lblException" runat="server"></asp:Label>
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<asp:UpdatePanel ID="pnlHelloWorld" runat="server">
					<ContentTemplate>
						<asp:Label runat="server" ID="lblHelloWorld" Text="Click the button!" />
						<br />
						<asp:Timer ID="dataThread" runat="server" Enabled="False" Interval="5000" 
							ontick="dataThread_Tick">
						</asp:Timer>
						<br />
						<asp:Button runat="server" ID="Button1" OnClick="Button1_Click" Text="Connect WCF" />
					</ContentTemplate>
				</asp:UpdatePanel>
			</td>
		</tr>
	</table>
</asp:Content>
 
Ich denke mit der Vermutung, dass die Seite neu lädt und die daten damit "verworfen" werden, liegst du richtig.
Versuche mal die WCF-Servicelogic in eine statische klasse aus zu lagern die du immer wieder aufrufst, bei mir klappt dass dann einwandfrei.
 
Tatsache... hat wirklich funktioniert mit der statischen Klasse.
Vielen Dank für die Hilfe :)
 
Zurück
Oben