silverlight+WCF的net.tcp雙工通訊實例過程html
注:本人只是一個菜鳥,有什麼不對的,請各位大俠指正,成分感謝!!!web
本實例實現一個簡單的單用戶對單用戶的消息發送實例。實例開始:express
說明:SilverlightApp silverlight項目,其網頁承載與WCF服務是一個WEB項目,即WcfService跨域
WcfContract 一個類庫項目,用於定義契約,需引用System.ServiceModel瀏覽器
WcfModel一個類庫項目,用於定義數據實體類,須要引用System.Runtime.Serialization服務器
WcfService 一個web項目,用於IIS寄存WCFdom
UserInfos.cssocket
namespace WcfModeltcp
{工具
[DataContract]
public class UserInfo
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
}
MessageInfo.cs
namespace WcfModel
{
[DataContract]
public class MessageInfo
{
[DataMember]
public UserInfo FromUser { get; set; }
[DataMember]
public UserInfo ToUser { get; set; }
[DataMember]
public string Content { get; set; }
[DataMember]
public DateTime SendTime { get; set; }
}
}
右鍵此項目,生成。
IMessageCallBack.cs
namespace WcfContract
{
public interface IMessageCallBack
{
[OperationContract(IsOneWay = true)]
void GetMessage(MessageInfo message);
}
}
IMessageManage.cs
namespace WcfContract
{
[ServiceContract(CallbackContract = typeof(IMessageCallBack))]
public interface IMessageManage
{
[OperationContract]
bool SendMessage(MessageInfo msg);
[OperationContract]
bool RequestMessage(UserInfo user);
}
}
右鍵此項目生成。
MessageService.cs
namespace WcfService
{
// 注意: 使用「重構」菜單上的「重命名」命令,能夠同時更改代碼、svc 和配置文件中的類名「MessageService」。
// 注意: 爲了啓動 WCF 測試客戶端以測試此服務,請在解決方案資源管理器中選擇 MessageService.svc 或 MessageService.svc.cs,而後開始調試。
public class MessageService :IMessageManage
{
//用於記錄用戶與對應的通道
private static Dictionary<int, IMessageCallBack> DicCallChannel = new Dictionary<int, IMessageCallBack>();
//記錄間用戶的ID
private int UserId = 0;
public bool SendMessage(WcfModel.MessageInfo msg)
{
//獲取對應要發送的通道,回調
if (DicCallChannel.Keys.Contains(msg.ToUser.Id))
{
DicCallChannel[msg.ToUser.Id].GetMessage(msg);
return true;
}
return false;
}
public bool RequestMessage(WcfModel.UserInfo user)
{
//獲取用戶請求創建的通道
IMessageCallBack channel = OperationContext.Current.GetCallbackChannel<IMessageCallBack>();
if (!DicCallChannel.Keys.Contains(user.Id))
{
DicCallChannel.Add(user.Id, channel);
UserId = user.Id;
OperationContext.Current.Channel.Closing += Channel_Closing;
}
return true;
}
//當用戶通道關閉時,把用戶的通道記錄刪除,即不記錄已經斷開的通道
void Channel_Closing(object sender, EventArgs e)
{
if (DicCallChannel.Keys.Contains(UserId))
{
DicCallChannel.Remove(UserId);
}
}
}
}
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="mBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="mBinding">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="WcfService.MessageService" behaviorConfiguration="mBehavior">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="mBinding" contract="WcfContract.IMessageManage" />
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="true" />
</system.webServer>
右鍵生成些項目
右擊應用程序池,添加應用程序池,命名爲WcfNetTcp,版本選擇.net framework v4.0.30319
點擊網站的高級設置在「已啓用的協議」中添加net.tcp
右擊網站,編輯協議-添加,選擇net.tcp,綁定信息輸入4507:*,肯定
點擊瀏覽網站,會列出以下信息
選擇MessageService.svc連接,也可直接在瀏覽器上輸入http://localhost:8081/MessageService.svc
瀏覽器會顯示以下:
已建立服務。
若要測試此服務,須要建立一個客戶端,並將其用於調用該服務。可使用下列語法,從命令行中使用 svcutil.exe 工具來進行此操做:
svcutil.exe net.tcp://barry:4507/MessageService.svc/mex
爲了讓WCF可以跨域,須要在IIS的默認網站根目錄下添加clientaccesspolicy.xml,有必要時還添加crossdomain.xml
clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*" />
</allow-from>
<grant-to>
<socket-resource port="4502-4534" protocol="tcp" />
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
crossdomain.xml
<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
IIS默認網站是Default Web Site根目錄是此網站的根目錄,地方要找正確
點擊引用,添加服務器引用,輸入net.tcp://localhost:4507/MessageService.svc/mex
在高級中,在字典信息類型中取消 從新使用引用的程序集中的類型
肯定添加
MainPage界面設計:
<UserControl x:Class="SilverlightApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<Button x:Name="btnCreateUser1" Content="生成用戶1" Width="100" Margin="0,10,0,0" Click="btnCreateUser1_Click" />
<Button x:Name="btnCreateUser2" Content="生成用戶2" Width="100" Margin="0,10,0,0" Click="btnCreateUser2_Click"/>
<TextBox x:Name="tbContent" Width="200" Height="150" Margin="0,10,0,0"/>
<Button x:Name="btnSend" Content="發送" Width="100" Margin="0,10,0,0" Click="btnSend_Click"/>
<TextBox x:Name="tbContentRecord" Width="200" Height="150" Margin="0,10,0,0"/>
</StackPanel>
</Grid>
</UserControl>
後臺代碼:
public partial class MainPage : UserControl
{
MessageInfo message = new MessageInfo();
public MainPage()
{
InitializeComponent();
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
MessageManageClient client = new MessageManageClient();
message.Content = tbContent.Text;
message.SendTime = DateTime.Now;
client.SendMessageAsync(message);
client.SendMessageCompleted += (ds, de) =>
{
if (de.Result)
{
MessageBox.Show("發送成功!");
}
else
{
MessageBox.Show("發送失敗!");
}
};
}
private void btnCreateUser1_Click(object sender, RoutedEventArgs e)
{
MessageManageClient client = new MessageManageClient();
UserInfo formUser = new UserInfo()
{
Id = 123,
Name = "張三"
};
UserInfo toUser = new UserInfo()
{
Id = 234,
Name = "李四",
};
message.FromUser = formUser;
message.ToUser = toUser;
message.Content = tbContent.Text;
message.SendTime = DateTime.Now;
client.RequestMessageAsync(formUser);
client.RequestMessageCompleted += (rs, re) =>
{
if (re.Result)
{
MessageBox.Show("用戶"+formUser.Id+"建立成功!");
}
};
client.GetMessageReceived += (gs, ge) =>
{
if (ge.Error == null)
{
tbContentRecord.Text += "\r" + "來自:" + ge.message.FromUser.Name + ",內容:" + ge.message.Content + ",時間:" + ge.message.SendTime.ToShortTimeString();
}
};
}
private void btnCreateUser2_Click(object sender, RoutedEventArgs e)
{
MessageManageClient client = new MessageManageClient();
UserInfo formUser = new UserInfo()
{
Id = 234,
Name = "李四"
};
UserInfo toUser = new UserInfo()
{
Id = 123,
Name = "張三",
};
message.FromUser = formUser;
message.ToUser = toUser;
message.Content = tbContent.Text;
message.SendTime = DateTime.Now;
client.RequestMessageAsync(formUser);
client.RequestMessageCompleted += (rs, re) =>
{
if (re.Result)
{
MessageBox.Show("用戶" + formUser.Id + "建立成功!");
}
};
client.GetMessageReceived += (gs, ge) =>
{
if (ge.Error == null)
{
tbContentRecord.Text += "\r" + "來自:" + ge.message.FromUser.Name + ",內容:" + ge.message.Content + ",時間:" + ge.message.SendTime.ToShortTimeString();
}
};
}
}
F5運行程序,複製頁面路徑,同時打開兩個相同的頁面
兩個頁面分別點生成用戶一、生成用戶2,
成功後,就可相互發送信息了
後記。對於net.tcp雙工有時候真心讓人不知道問題在那兒,什麼跨域XML。配置文件這些都沒問題,有時候就是仍是要報什麼跨域錯誤,有時候又不報跨域錯誤,真讓人摸不着頭腦,若是有對此瞭解深入的,請大神指點。
源碼地址:
http://download.csdn.net/detail/cyb331/5657061源碼不當心加上分了,須要的留下郵箱