进入新公司需要新技能。以前从来没用过C#,但是现在的项目是Lync API开发,只能抓紧从头开始了。
网络上关于UCMA4的文章并不多,微软的网站上可能有不少,还有一些视频,不过并不适合入门。有一个视频除外,我也是从这个视频开始学的:http://channel9.msdn.com/posts/UCMA-Hello-World-Send-an-Instant-Message (UCMA Hello World - Send an Instant Message)
虽然入门教程不多,但是概念讲解的还不少。比如这个:http://www.cnblogs.com/vipyoumay/archive/2012/01/12/2320801.html
http://msdn.microsoft.com/library/office/dn465943(office.15)
你可以选择先看看上面的东西,详细了解下,然后接着读这篇文章。
UCMA4和UCMA3有什么区别我不知,因为我每接触过后者,不过后者的用户群应该远大于前者。
UCMA4的连接搭建流程很清晰,直接看代码。下面的代码和视频里的基本一致:
class Program { string conversationSubject = "let's go"; string messageText = "it's a sunny day."; InstantMessagingCall imCall; InstantMessagingFlow imFlow; UserEndpoint userEndpoint; UCMASampleHelper helper; AutoResetEvent completeEvent = new AutoResetEvent(false); ...
在使用之前先来几个变量。字符串的不说了,你看下哪里用到就知道干什么的了。
ucma中有两种“终端”:USERENDPONT和APPLICATIONENDPOINT。第二个功能更强大也更难用,目前也不需要。可以自己看一下:http://blog.thoughtstuff.co.uk/2014/01/ucma-endpoints-choosing-between-application-and-user-endpoints/
因为我们使用UCMA是希望和Lync客户端进行通信,所以需要一个发起通信的客户端(当然是用API模拟的)。这个对象对应的类就是UserEndpoint,所以我们建立一个他的对象userEndpoint。上面的两个对象,imCall是InstantMessagingCall的实例,用了建立连接的(是和另一个客户端的连接,不是和服务器的)。imFlow是InstantMessagingFlow的实例,用了处理业务的,比如这里要发送的消息。
为了简化,这里用到了UCMASampleHelper类。视频里很详细的说了怎么引入该类:
using Microsoft.Rtc.Collaboration.Sample.Common; ... namespace Microsoft.Rtc.Collaboration.Sample.Common { class UCMASampleHelper {
你可以把using子句去掉,改成:
namespace xxx//xxx和Program类是一样的 { class UCMASampleHelper {
completeEvent是多线程里的一个信号量。我刚刚接触C#,UCMA里用到不少异步、委托、多线程的技能,我不是很了解他们和java中的区别,所以不多说了。估计看这篇文章的都比我懂。
在主要的Run方法里,操作如下:
... private void Run() { helper = new UCMASampleHelper(); userEndpoint = helper.CreateEstablishedUserEndpoint("hello_world"); Console.WriteLine("the endpoint is owned by " + userEndpoint.OwnerUri); ConversationSettings conversationSettings = new ConversationSettings(); conversationSettings.Subject = conversationSubject; Conversation conversation = new Conversation(userEndpoint, conversationSettings); imCall = new InstantMessagingCall(conversation); imCall.InstantMessagingFlowConfigurationRequested += new EventHandler<InstantMessagingFlowConfigurationRequestedEventArgs>(imCall_InstantMessagingFlowConfigurationRequested); string targetUri = "sip:a.b.c@def.com"; imCall.BeginEstablish(targetUri, null, CallEstablishCompleted, null); completeEvent.WaitOne(); } ...
工具类里的CreateEstablishedUserEndpoint方法用于和服务器进行连接。下面再说这里。
终端连接后,就把他传给一个会话Conversation。UCMA里的对象多数建立的时候需要配置信息,所以这个会话也要一个ConversationSettings的实例。会话conversation生成后用来生成imCall。imCall中包含了第一个客户端的信息,所以还需要对方。通过sip协议指定一个对象targetUri(估计需要是同域的,不然连lync都连不上吧),然后调用imCall的BeginEstablish方法进行请求,成功后就调用CallEstablishCompleted方法。imcall一建立就会调用InstantMessagingFlowConfigurationRequested,我们给他委托一个事件,定义在方法imCall_InstantMessagingFlowConfigurationRequested里:
void imCall_InstantMessagingFlowConfigurationRequested(Object sender,InstantMessagingFlowConfigurationRequestedEventArgs e) { imFlow = e.Flow; imFlow.StateChanged += new EventHandler<MediaFlowStateChangedEventArgs>(imFlow_StateChanged); imFlow.MessageReceived += new EventHandler<InstantMessageReceivedEventArgs>(imFlow_MessageReceived); }
imFlow状态改变时也有一个事件,定义在imFlow_StateChanged里:
void imFlow_StateChanged(object sender, MediaFlowStateChangedEventArgs e) { if (e.State == MediaFlowState.Active) { imFlow.BeginSendInstantMessage(messageText, SendMessageCompleted, imFlow); } }
MediaFlowState有三个枚举:Idle,Active,Terminated。当变成Active时就发消息it's a sunny day.
收到消息时的事件处理定义在imFlow_MessageReceived中:
void imFlow_MessageReceived(object sender, InstantMessageReceivedEventArgs e) { if (e.TextBody.Equals("using lync", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("success,,, hello."); } else if (e.TextBody.Equals("bye", StringComparison.OrdinalIgnoreCase)) { imFlow.BeginSendInstantMessage("shutting down...", SendMessageCompleted, imFlow); helper.ShutdownPlatform(); } else { imFlow.BeginSendInstantMessage("ECHO: " + e.TextBody, SendMessageCompleted, imFlow); } }
很简单,对方给你回复using lync时控制台打印success,,, hello.回复bye时你自动回复shutting down...然后关掉;回复其他内容,你都自动回复ECHO:加他的内容。
其他回调方法为空。
上面主要是这个视频的内容。但是有一部分很需要留意:终端登录时怎么设置参数?
既然你要模拟一个客户端,你就需要一个用户名和他的密码,还要提供你要登录哪个服务器,你是在哪个域。
视频里没有讲到这一块,他演示了怎么获得一个App.config。
一个短的App.config是这样的:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <!-- Please provide parameters necessary for the sample to run without prompting for input --> <!-- Provide the FQDN of the Microsoft Lync Server --> <!--<add key="ServerFQDN1" value="ServerFQDN"/>--> <!-- The user name of the user that the sample logs in as --> <!-- You may leave this value as blank to use credentials of the currently logged on user --> <!--<add key="UserName1" value="user"/>--> <!-- The user domain of the user that the sample logs in as --> <!-- You may leave this value as blank to use credentials of the currently logged on user --> <!--<add key="UserDomain1" value="domain"/>--> <!-- The user URI of the user that the sample logs in as, in the format user@host --> <!--<add key="UserURI1" value="user@host"/>--> </appSettings> <runtime> ... </runtime> </configuration>
这些参数不配置的话可以在控制台里交互。如果提供的话去掉注释就好,当然自己要改参数值。比如:
<add key="ServerFQDN1" value="lync.miclozoft.com"/> <add key="UserName1" value="c.b.a"/> <add key="UserDomain1" value="ads.adsk.com"/> <add key="UserURI1" value="b.c.a@adsk.com"/>
注意不要删掉数字后缀。
如果你提供的参数都是正确的,那就可以通信和发消息了。