摘要:本文档将介绍从最初建造一个application manifest到最终安装和管理SIP application的详细过程,并提供示例代码,以演示开发扩展LCS应用的具体方法。
Live Communications Server Application API应用
1 在新的服务器布局里开发应用程序
Live Communications Server 2005支持新的服务器角色,包括:Standard Edition, Enterprise Edition, Enterprise Edition Pool, Enterprise Edition Back End Storage, Archiving Service, Director, Proxy, and Access Proxy。第三方应用程序能配置到上述任意或全部服务器上,以满足想得到的功能性。理解每个新的服务器角色的功能是开发和设计应用程序的要点。
2 建立一个Application Manifest
以LCS默认核心消息过滤脚本为例(此脚本原始位置:..\Program Files\Microsoft LC 2005\Server\ routing.am):
这个MSPL脚本过滤引入的SIP消息,并且以端点ID(EDID)、可用性合计、活动性数值和AgeOfPresence数值为基础,尝试为每一个消息选择出最好的端点。端点没有注册存在或者可用性合计小于100的将不被考虑。
示例代码
<?xml version="1.0">
<lc:applicationManifest
lc:appUri="http://www.my_domain_here.com/DefaultRoutingScript"
xmlns:lc="http://schemas.microsoft.com/lc/2003/05">
<lc:requestFilter methodNames="INVITE,MESSAGE,INFO,REFER,ACK,BYE,OTHER"
strictRoute="false"
registrarGenerated="true"
domainSupported="true"/ >
<lc:responseFilter reasonCodes="NONE" />
<lc:proxyByDefault action="true" />
<lc:scriptOnly />
<lc:splScript><![CDATA[
//Log函数向LCS指定Server Log写入调试Log,具体内容除消息内容之外的全部消息。
Log( "Debug", 1, "we have a request - ", sipRequest.Method );
//Ge tUri方法返回消息头中的“To”
toUri = GetUri( sipRequest.To );
//Concatenate方法将用GetUserName得到的Sip中的toUri与@与GetHostName中的HostName
//组合成toUserAtHost
toUserAtHost = Concatenate( GetUserName( toUri ), "@", GetHostName( toUri ) );
// rameterValue方法返回消息头重指定的参数”EPID”的值。
requestEPID = GetParameterValue( sipRequest.To, "EPID" );
//定义变量并赋初值
bestEPID = "";
bestAgeOfPresence = 0x7FFFFFFF;
bestAvailability = 0;
bestActivity = 0;
bestContactInfo = "";
Log( "Debug", 1, "EPID - ", requestEPID );
Log( "Debug", 1, "toUserAtHost - ", toUserAtHost );
//循环全部端点
foreach (dbEndpoint in QueryEndpoints( toUserAtHost, true )) {
Log( "Debug", 1, " endpoint.EPID - ", dbEndpoint.EPID );
Log( "Debug", 1, " endpoint.HasPresence - ", dbEndpoint.HasPresence );
Log( "Debug", 1, " endpoint.Availability - ", dbEndpoint.Availability );
Log( "Debug", 1, " endpoint.Activity - ", dbEndpoint.Activity );
Log( "Debug", 1, " endpoint.AgeOfPresence - ", dbEndpoint.AgeOfPresence );
Log( "Debug", 1, " endpoint.ContactInfo - ", dbEndpoint.ContactInfo );
// 第一步,用SupportsMethod函数确定SIP方法是否被应用程序支持。
if (!SupportsMethod( sipRequest.Method, dbEndpoint.StandardMethods, dbEndpoint.ExtraMethods )) {
//跳出这个端点,因为不能处理请求的方法。
Log( "Debug", 1, " * skipped because of method" );
continue;
}
if (requestEPID != "") {
if (requestEPID == dbEndpoint.EPID) {
//这个请求已经把一个能处理这个方法的端点当作目标,所以用这个端点。
Log( "Debug", 1, " * matched EPID" );
//给前面定义的变量赋值
bestContactInfo = dbEndpoint.ContactInfo;
break;
}
else {
//请求已确定EPID,但不匹配,跳出这个端点,继续执行。
Log( "Debug", 1, " * skipped because of EPID" );
continue;
}
}
if (!dbEndpoint.HasPresence ||
dbEndpoint.Availability < 100 ||
dbEndpoint.ContactInfo == ""
) {
//如果在ContactInfo字段中没有在线,或者状态为“offline”,或者没有路由信息,跳出这个端点
Log( "Debug", 1, " * skipped because of presence, activity or contactinfo" );
continue;
}
if (dbEndpoint.Availability < bestAvailability) {
//如果没有可用性条出这个端点
Log( "Debug", 1, " * skipped because of availability" );
continue;
}
if (dbEndpoint.Availability == bestAvailability) {
if (dbEndpoint.Activity < bestActivity) {
//如果这个端点活跃性小于1,跳出这个端点
Log( "Debug", 1, " * skipped because of activity" );
continue;
}
……(略)
3 为Live Communications Server 创建一个SIP应用程序
3.1 Setting up a Server Agent
server agent是你的应用程序和LCS之间的公共点。它是用ServerAgent类定义的对象,由它通过LCS代表你的应用程序发送和接收消息。
配置一个 LCS Agent的第一步是建立一个application manifest并编译。这个application manifest将要运行在服务器上并且通过消息过滤脚本仅接收你的应用程序感兴趣的SIP消息。这个动作是通过执行你的应用程序的Main方法实现的。例如下面代码:
using System.Threading;
using System.Resources;
using Microsoft.Rtc.Sip;
// 在这个例子中获取包含你的application manifest的XML string,
// 这个XML string //像资源一样包含在应用程序装配件中,用
// ResourceManager.GetString(resourceName)方法得到。
ResourceManager myResourceManager = new ResourceManager(myApplicationClass);
//” appManifest”是你的application manifest XML 文件的名字,像添加应用程序// 的资源一样的添加它。
string myAppManifestXmlString = myResourceManager.GetString("appManifest");
ApplicationManifest myAppManifest = new ApplicationManifest(myAppManifestXmlString);
try {
//编译
myAppManifest.Compile();
}
//异常处理
catch (CompilerErrorException cee) {
Console.WriteLine("The following errors occurred during compilation:");
foreach (string errorMessage in cee.ErrorMessages) {
Console.WriteLine("--- {0}", errorMessage);
}
}
在实例化ServerAgent的时候提供ApplicationManifest对象,ServerAgent的构造函数会编译这个Application Manifest.例如下面代码。
try {
ServerAgent myAppServerAgent = new ServerAgent(myAppManifest);
}
catch (NullReferenceException nre) {
Console.WriteLine("The application manifest is uncompiled and ServerAgent cannot be instantiated.");
}
catch (ServerNotFoundException snfe) {
Console.WriteLine("The Live Communications Server is not available.");
}
应用程序必须从消息过滤中分配句柄信息,同时,还必须建立一个类和这个句柄的方法对应。例如下面代码,如果你有一个call在你的消息过滤器里。
Dispatch("OnInviteReceived");
在你的定义的类上必须有一个相应的OnInviteReceived方法。
3.2 Processing Server Events
当Dispatch被脚本呼叫过,一个服务器事件便被触发。
3.3 Handling Messages from the Live Communications Server
当LCS收到消息,application manifest必须有特定的转发给相应得应用程序。
例如在application manifest中有下列代码:
if (sipRequest.Method == "MESSAGE")
Dispatch("OnMessageReceived");
Respond(200);
}
上述代码功能是, 当LCS分配SIP消息类型为“MESSAGE”的消息给“OnMessageReceived”你的应用程序的事件句柄,定义事件句柄的代码示例如下:
public void OnMessageReceived(object sender, RequestReceivedEventArgs requestEventArgs) {
// Obtain the Request object to process from RequestReceivedEventArgs.
Request request = requestEventArgs.Request;
// Obtain the new server transaction for this request.
ServerTransaction myServerTransaction = requestEventArgs.ServerTransaction;
// Processing logic here.
//
// Create a branch on the server transaction to forward the request.
try
{
// Attempt to send the request.
requestEventArgs.ServerTransaction.CreateBranch();
requestEventArgs.SendRequest(request);
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception: {0}\n{1}",
e.Message,
e.StackTrace);
}
}
参考文档《Microsoft Office Live Communications Server 2005》