MSPL (and its managed cousin, which goes by various names) is an extremely powerful tool for customizing Lync Server routing behavior. It can also, at times, be extremely frustrating to troubleshoot, partly because of the complexity of tinkering with the way Lync routes messages, and partly because the debugging tools we’re accustomed to for most .NET development are unavailable with MSPL. One of the most common frustrations I hear from people working with MSPL development is that messages that the script should be picking up and handling are just not going through the script at all. They’re visible in SIP logs, they’re obviously there, but your script somehow doesn’t see them. This post is my attempt to summarize a few of the most common reasons this can happen, and what you can do about it.
Method names or response codes
This probably goes without saying, but I figured it was worth mentioning for completeness. The application manifest for your MSPL script needs to have a <requestFilter> and <responseFilter> element, and each one has an attribute specifying method names (for requests) and reason codes (for responses) that you want to catch. If your script isn’t seeing some of the messages you want it to handle, make sure you are filtering to the right method names and reason codes. Here’s a typical, very simple <requestFilter> element:
<br /><lc:requestFilter methodNames="INVITE,MESSAGE" /><br />
In this instance, for example, the script would not pick up INFO messages. To see those, you’d need to change the methodNames attribute to add INFO, or change the value to ALL.
The domainSupported attribute
There are a few other attributes that you can add to the <requestFilter> element. One of these that has always confused me a bit is the domainSupported attribute. According to the documentation, the purpose of this attribute is to control whether requests coming from SIP domains that are supported by the registrar on which the script is running are handled by the script. The way the docs are worded, it sounds like setting this value to true should give your script visibility to a larger number of requests: the ones from locally supported SIP domains, and the ones from other SIP domains. In my experience, it SEEMS to do something like the reverse: if you set it to true, it seems to only allow your script to see requests from locally supported SIP domains, while if it’s set to false you can see requests from any SIP domain. I haven’t yet figured out why this is, but you may want to try adding domainSupported=”false” to your request filter if you are missing some important requests (the default value is true).
<br /><lc:requestFilter methodNames="INVITE,MESSAGE" domainSupported="false" /><br />
The strictRoute attribute
Less contradictory, but equally bewildering, is the strictRoute attribute. This one controls whether your script gets to see requests that have a strict route already assigned when it’s your application’s turn to deal with them.
To explain what a strict route means, let me add a bit of context. When a request arrives at a Front End Server, it’s the Front End’s job to look at the SIP URI in the To header and figure out where this request should be sent – what the actual network location is that the message should be routed to, based on the identity of the destination user. It’s a bit like looking up people’s phone numbers in the phone book based on their names.
MSPL applications, including the ones built in to Lync Server, often play important supporting roles in this process. They can look at a request, and stamp it with a request URI that specifically identifies where the request needs to be routed to. Alternatively, they might add a Route header, or add an maddr URI parameter to the To header. The presence of any of these means the request has a “strict route.”
MSPL-based applications have a sequence in which they get to look at and handle messages. This sequence is determined by the priority value assigned to each application. You assign priority values via Lync Management Shell, using the -Priority parameter in New-CsServerApplication or Set-CsServerApplication. Lower priority values mean an application that is earlier in line.
Sometimes, by the time it’s your application’s turn to look at a request, that request has already been given a request URI, and therefore a strict route, by an application earlier in the sequence. In MSPL, you do this by calling ProxyRequest and passing in a parameter, like this:
<br />ProxyRequest("sip:email@example.com;opaque=user:epid:UghFocauauCHBHoLhAAA;gruu)<br />
Other times, a request will arrive at the Front End Server with a strict route already assigned, maybe by an application in another pool.
Regardless, if your application is set to NOT handle requests with a strict route, which is the default, then you won’t see any of these messages. Requests that have been proxied and given request URIs by applications earlier in the sequence will never make it to your application.
Set strictRoute to true if you DO want to see these requests:
<lc:requestFilter methodNames="INVITE,MESSAGE" domainSupported="false" strictRoute="true" />
Keep in mind that this means your application will have to process many more requests, and that it can seriously mess things up if it changes or reroutes requests that have already been routed by a script internal to Lync Server.
Finally, you also have the option of changing the priority value itself in order to determine where your script is in the sequence. You can move it earlier in the sequence to handle requests before other scripts have a chance, or you can move it later in sequence to see requests when they have already received some processing from other scripts, including the ones built into Lync like the translation service.
Changing your priority value to a higher number (therefore moving your script later in the sequence) while also setting the strictRoute attribute to true can allow you to see messages after more of the standard Lync Server processing is done but still modify or reroute them.
Use the Set-CsServerApplication command in Lync Server Management Shell to make this change.
One important note: if you want your script to come before the UserServices application in sequence, you will need to add another element to the application manifest: allowRegistrationBeforeUserServices.
This element must be present and set to true, or else your script will fail to load when placed earlier in priority order than UserServices. Here’s an example:
<lc:requestFilter methodNames="INVITE,MESSAGE" domainSupported="false" strictRoute="true" /> <lc:allowRegistrationBeforeUserServices="true" />
Hopefully the suggestions here will save a few of you from some long and frustrating troubleshooting sessions. If you have issues with an MSPL script not seeing certain messages that is not covered here, feel free to post in the comments.