views:

144

answers:

5

Sorry for asking a question about something I don't know much about, but I've been pulling my hair out trying to get this working.

So, I have a WCF service that is hosted on IIS and seems to be working insomuch that I can "see" it on the network by going to http://servername/MyService.svc in a browser.

That .svc looks like:

<% @ServiceHost Service="Foo.Bar" %>

The relevant code looks like:

    [ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06Services/Notification/03")]
    public interface IBar
    {
        [OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*")]
        [XmlSerializerFormat(Style = OperationFormatStyle.Document)]
        void Notify(string eventXml, string tfsIdentityXml);
    }

and:

public class Bar : IBar
{
    public void Notify(string eventXml, string tfsIdentityXml)
    {
        // Just some test output to see if it worked
        var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "tfs.txt");
        File.WriteAllText(path, tfsIdentityXml + eventXml);
    }
}

That's all been built and the ensuing .dll put into the bin dir in the site root in IIS.

I now want to subscribe via bissubscribe.exe (or a similar method) to TFS check-in events. I tried doing something like:

bissubscribe /eventType CheckinEvent 
  /address http://servername/MyService.svc
  /deliveryType Soap 
  /server mytfsserver

But nothing; it doesn't even look like there was log activity. So keeping in mind I know nothing about WCF, what am I doing wrong? I imagine the address param is one thing; am I not supposed to point it to the .svc?

+1  A: 

One point that jumps out is the fact you have a method that doesn't return anything except void. Those should be marked as "one-way" method in WCF:

[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06Services/Notification/03")]
public interface IBar
{
    [OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*", IsOneWay=true)]
    [XmlSerializerFormat(Style = OperationFormatStyle.Document)]
    void Notify(string eventXml, string tfsIdentityXml);
}

Add the "IsOneWay=true" to your [OperationContract] attribute.

Other than that, there's nothing obviously wrong in your code, but to really tell, we'd need a lot more config info to really tell. Try the IsOneWay=true first and see if that solves your issue.

marc_s
Alright, I can do that--but more than anything, I'm curious what the "URL" of my service is. I know it's a dumb question, but is that one I posted (the .svc) the right way for clients to access it? Or how is that generally done?
J Cooper
Ah okay - sorry, didn't catch that part of the question :-) When hosting in IIS, the URL of the service is defined by the server (and possibly a port), the virtual directory and possible subdirectories under that where the *.svc file lives, and the name and extension of the svc file itself. So it would be something like `http://yourserver:8088/virtualdir/subdir/yourservice.svc`
marc_s
Add to that url any possible relative "address" you might have defined in your service configuration file (the web.config of the site, in the `<system.serviceModel><services>....` section
marc_s
+1  A: 

How is your service configured? In particular, is it configured to use basicHttpBinding?

Try creating a client to call your service to make sure it can be called.

Then, see if there's an example service from the TFS SDK - see if you can get the example to work.

John Saunders
The TFS examples for notifying services seem to point to a .asmx file, which I don't have. I assume that's not WCF; what's the equivalent?
J Cooper
Do you _have_ the sample ASMX file? That's what I want you to use, to diagnose where the problem lies.
John Saunders
+1  A: 

I was able to complete this connection with the following:

[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface ITeamSystemObserver : IObservable
{
    [OperationContract( Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*" )]
    [XmlSerializerFormat(Style=OperationFormatStyle.Document)]
    void Notify(string eventXml, string tfsIdentityXml, SubscriptionInfo SubscriptionInfo);
}

Note you are missing the SubscriptionInfo parameter. Here is my web.config:

 <basicHttpBinding>
    <binding name="TfsEventServiceBasic">
      <security mode="TransportCredentialOnly">
        <transport clientCredentialType="Ntlm" />
      </security>
    </binding>
  </basicHttpBinding>
Adam Fyles
Thank you; I added these changes. I'm still getting an HTTP 405 error from BisSubscribe.exe though, for some reason
J Cooper
+1  A: 

TFS 2010 and WCF 4.0 configurations are described below...

Method signature:

public void Notify(string eventXml) /* No SubscriptionInfo! */

Web config:

<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="Microsoft.TeamFoundation, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
      </assemblies>
    </compilation>
  </system.web>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="NotificationServiceBehavior" name="TF.CheckinListener.CheckinListener">
        <endpoint address="Notify" binding="wsHttpBinding" bindingConfiguration="noSecurity" contract="TF.CheckinListener.ICheckinListener" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="NotificationServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
    </binding>
      <wsHttpBinding>
        <binding name="noSecurity" maxBufferPoolSize="20000000" maxReceivedMessageSize="200000000">
      <readerQuotas maxStringContentLength="200000000" maxArrayLength="200000000" />
      <security mode="None" />
    </bindings>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

Subscription address for bissubscribe:

http://MachineName/VirtualDirectoryName/Service.svc/Notify

Cicekfidan
+1  A: 

I have created a blog post how you can use WCF in combination with the Event Services of TFS: http://www.ewaldhofman.nl/post/2010/08/02/How-to-use-WCF-to-subscribe-to-the-TFS-2010-Event-Service-rolling-up-hours.aspx

Ewald Hofman