Use the IOfferAnswer interface in the Unified Communications Managed API version 1.0 SDK to make communication enabled business processes available via Instant Messaging. For example, send a stock ticker to get a price quote, or supply a tracking number to get a parcel's delivery status. Additional services may include scanning RSS (Really Simple Syndication) feeds through the conversation window of Microsoft Office Communicator.

In this walkthrough the application requests a current share price by sending a stock ticker symbol to a service. For a more complete example of a similar scenario, see the BroadcastIM sample application included with the SDK.

Prerequisites

Open a New Project

Create a new Microsoft Windows Visual C# application.

To create the Unified Communications Managed API version 1.0 project

  1. Open a new Visual C# project in Microsoft Visual Studio 2005. Select Windows Application as the project type. Name the project AutomatedServices.

  2. Add a reference to Microsoft.Rtc.Collaboration.dll, which is installed at %ProgramFiles%\Office Communications Server 2007\UCMA v1.0.

  3. Add a new class to the project. Name the file AutomatedServices.cs

  4. In the Toolbox, click Components to display components available to add to Visual C# designers.

  5. Drag and drop a BackgroundWorker component onto the design surface for the form.

  6. Add controls to the form. Use the property settings specified in the following table.

    Controls Property Property Value

    textBox

    Name

    textBoxDomainName

    Label

    Text

    Domain Name

    textBox

    Name

    textBoxSipUri

    Label

    Text

    SIP URI

    Button

    Name

    buttonSet

    Button

    Text

    Set

    Button

    Name

    buttonSend

    Button

    Text

    Send

Add Code

Add code to the form.

To add code to Form1

  1. Add the following using statement to Form1.

    Copy Code
    using Microsoft.Rtc.Signaling;
    
  2. Add the following declarations above the Form1 constructor.

    Copy Code
    internal SipEndpoint m_SipEndPoint;
    RealTimeServerConnectionManager m_RealTimeServerConnectionManager;
    private AutomatedServices m_Services;
    
  3. Double-click the Set button and then add the following code to the button's event handler.

    Copy Code
    m_RealTimeServerConnectionManager = (RealTimeServerConnectionManager)new RealTimeServerTcpConnectionManager();
    m_SipEndPoint = new SipEndpoint(textBoxSipUri.Text, SipAuthenticationProtocols.Kerberos, SipTransportType.Tcp, textBoxDomainName.Text);
    
  4. Double-click the Send button and then add the following statement to the button's event handler.

    Copy Code
    string stockTicker = "myStockTickerSymbol";
    m_Services = new AutomatedServices(stockTicker, m_SipEndPoint, backgroundWorker1);
    

To add code to AutomatedServices.cs

  1. Add the following using statements to AutomatedServices.cs.

    Copy Code
    using Microsoft.Rtc.Signaling;
    using System.ComponentModel;
    using System.Net;
    using System.Net.Mime;
    
  2. Replace the AutomatedServices class with the following code.

    Copy Code
    public class AutomatedServices : IOfferAnswer
    {
    }
    
  3. Add the following declarations at the top of the body of the AutomatedServices class.

    Copy Code
    private String m_Notification;
    private SipEndpoint m_Endpoint;
    private BackgroundWorker m_Worker;
    
  4. Add the following constructor to the AutomatedServices class.

    Copy Code
    public AutomatedServices(String Notification, SipEndpoint endpoint, BackgroundWorker Worker)
    {
      //Stock ticker.
      m_Notification = Notification;
    
      //Validate the endpoint.
      if (endpoint != null)
      {
    	m_Endpoint = endpoint;
      }
    
      else
      {
    	throw new InvalidOperationException("Cannot pass a null endpoint to the Notification Operation");
      }
    
      //Store the URI the ticker symbol is sent to.
      Target To = new Target();
      To.SipUri = "sip:someone@example.com";
    
      //Send the message.
      m_Worker = Worker;
      SignalingSession Session = new SignalingSession(m_Endpoint, new RealTimeAddress(To.SipUri));
      Session.LocalParticipant.ApplicationContext = To;
      Session.OfferAnswerNegotiation = this;
      Session.MessageReceived += this.MessageReceived;
      Session.BeginParticipate(ParticipateCallback, Session);
    }
    
  5. Add the following event handler to the class.

    Copy Code
    private void MessageReceived(object sender, MessageReceivedEventArgs e)
    {
      SignalingSession session = sender as SignalingSession;
      ContentType contentType = e.ContentType;
      MessageType messageType = e.MessageType;
      string message = String.Empty;
    
      if (contentType.MediaType.CompareTo("text/plain") == 0 && contentType.CharSet.CompareTo("utf-8") == 0)
      {
    	message = Encoding.UTF8.GetString(e.GetBody());
      }
    }
    
  6. Add the following members to the AutomatedServices class.

    Copy Code
    private void ParticipateCallback(IAsyncResult ar)
    {
      SignalingSession Session = ar.AsyncState as SignalingSession;
      Target To = Session.LocalParticipant.ApplicationContext as Target;
      SipMessageData Response = null;
    
      try
      {
    	Response = Session.EndParticipate(ar);
      }
      catch (OperationTimeoutException e)
      {
    	string msg = e.ToString();
      }
      catch (FailureResponseException e)
      {
    	string msg = e.ToString();
      }
      catch (ConnectionFailureException e)
      {
    	string msg = e.ToString();
      }
      catch (RealTimeException e)
      {
    	string msg = e.ToString();
      }
      finally
      {
    	if (Response != null)
    	{
    	Session.BeginSendMessage(MessageType.Message, new ContentType("text/plain"), Encoding.UTF8.GetBytes(m_Notification), SendMessageCallback, Session);
    }
      }
    }
    
    private void SendMessageCallback(IAsyncResult ar)
    {
      SignalingSession Session = ar.AsyncState as SignalingSession;
      SipResponseData Response = null;
    
      try
      {
    	Response = Session.EndSendMessage(ar);
      }
      catch (FailureResponseException e)
      {
    	string msg = e.ToString();
      }
      catch (OperationTimeoutException e)
      {
    	string msg = e.ToString();
      }
      catch (RealTimeException e)
      {
    	string msg = e.ToString();
      }
      finally
      {
    	Session.BeginTerminate(TerminateCallback, Session);
      }
    }
    
    private void TerminateCallback(IAsyncResult ar)
    {
      SignalingSession Session = ar.AsyncState as SignalingSession;
      Session.EndTerminate(ar);
    }
    
    public ContentDescription GetAnswer(object sender, ContentDescription offer)
    {
      return null;
    }
    
    public void HandleOfferInReInvite(object sender, OfferInReInviteEventArgs e)
    {
      return;
    }
    
    public void HandleOfferInInviteResponse(object sender, OfferInInviteResponseEventArgs e)
    {
      return;
    }
    
    public ContentDescription GetOffer(object sender)
    {
      SignalingSession Session = sender as SignalingSession;
      IPAddress IpAddress;
    
      // This method is called back every time an outbound INVITE is sent.
      if (Session.Connection != null)
      {
    	IpAddress = Session.Connection.LocalEndpoint.Address;
      }
      else
      {
    	IpAddress = IPAddress.Any;
      }
    
      Sdp<SdpGlobalDescription, SdpMediaDescription> SessionDescription = new Sdp<SdpGlobalDescription, SdpMediaDescription>();
    
      //Set the origin line of the SDP
      //s, t, and v lines are automatically constructed
      SessionDescription.GlobalDescription.Origin.Version = 0;
      SessionDescription.GlobalDescription.Origin.SessionId = "0";
      SessionDescription.GlobalDescription.Origin.UserName = "-";
      SessionDescription.GlobalDescription.Origin.Connection.Set(IpAddress.ToString());
    
      //Set the connection line
      SessionDescription.GlobalDescription.Connection.TrySet(IpAddress.ToString());
    
      SdpMediaDescription mditem = new SdpMediaDescription("message");
    
      mditem.Port = 5060;
      mditem.TransportProtocol = "sip";
      mditem.Formats = "null";
    
      SdpAttribute aitem = new SdpAttribute("accept-types", "text/plain");
    
      mditem.Attributes.Add(aitem);
    
      //Append the Media description to the Global description
      SessionDescription.MediaDescriptions.Add(mditem);
    
      ContentType ct = new ContentType("application/sdp");
    
      return new ContentDescription(ct, SessionDescription.GetBytes());
    }
    
    public void SetAnswer(object sender, ContentDescription answer)
    {
      return;
    }
    
  7. Add the Target class to AutomatedServices.cls.

    Copy Code
    //This class stores the SIP URI
    // receiving the service request.
    public class Target
    {
      string m_SipUri;
      public string SipUri
      {
    	get
    	{
    	return m_SipUri;
    }
    
    	set
    	{
    	SipUriParser TargetUri;
    
    	if (SipUriParser.TryParse(value, out TargetUri))
    	{
    		m_SipUri = value;
    }
    
    	else
    	{
    		throw new InvalidOperationException("Cannot assign the current value");
    }
    }
      }
    }
    
  8. Build the solution.

To run the application

  1. Add your sample to the authorized list of hosts on Office Communications Server and then enable server throttling.

  2. Ensure that the application user is an authenticated user on Office Communications Server.

  3. Press F5.

  4. On Form1, in Domain Name enter the domain name of the Office Communications Server.

  5. In SIP URI enter a URI using this style: sip:someone@example.com. The URI should reference an actual Active Directory account.

  6. Click Set, and then click Send.

See Also