Tuesday, August 21, 2007

Not so simple SharePoint and CRM integration

A customer of mine wanted to integrate their MOSS Ent with CRM 3. Specifically they wanted to be able to handle documents in CRM with SharePoint, not surprising since the document handling in MS CRM 3 is bad, if you are a bit positive. They were running 2 servers, one with CRM and one with MOSS Ent. Both with their own SQL 2005 installations (to avoid problems with SPN:s and such).

The solution? I based the solution on my previous posting from October 2006 where I described how to do this; Simple SharePoint and CRM integration (http://gustafwesterlund.blogspot.com/2006/10/simple-crm-and-sharepoint-integration.html). That was WSS 2 and both applications were running on the same server. So, not really the same setup, but, I felt, it shouldn't be a problem.

My plan was to create a SharePoint site using a specific custom template on the Account PostCreate callout. The callout would set the websiteurl attribute and an onLoad javascript would show a custom aspx-page that shows a documents webpart using the minimal.master (in order to hide all the SharePoint specific framing).

I started off by creating the PostCreate callout. Not a problem, just create a normal class file with the following content:

using System;

using Microsoft.Crm.Callout;

using Callouts.CRMSDK;


 

namespace Callouts

{

           ///
<summary>

           /// Summary description for Class1.

           ///
</summary>

           public
class Account: CrmCalloutBase       

           {

                      public Account()

                      {

                      }

                      public
override
void PostCreate(CalloutUserContext userContext, CalloutEntityContext entityContext, string postImageEntityXml)

                      {

                     
 

                                 CrmService service = new CrmService();

                                 service.Credentials = System.Net.CredentialCache.DefaultCredentials;


 

                                 service.CallerIdValue = new CallerId();

                                 service.CallerIdValue.CallerGuid = userContext.UserId;


 

                                 systemuser user = (systemuser)service.Retrieve(EntityName.systemuser.ToString(), userContext.UserId, new AllColumns());

                                 account acc = (account)service.Retrieve(EntityName.account.ToString(), entityContext.InstanceId, new AllColumns());       


 

// Code to create sharepoint site/subweb and set acc.websiteurl to the url.

                                 service.Update(acc);


 

                      }


 

           }

}


 

And add a web reference to the CRM webservice (look in the SDK to find the exact URL). As you probably can see, I called it CRMSDK (strange name actually, but it´s tradition).

And the callout.config.xml looked like this:

<callout.config
version="3.0"
xmlns="http://schemas.microsoft.com/crm/2006/callout/">

           <callout
entity="account"
event="PostCreate">

                      <subscription
assembly="Callouts.dll"
class="Callouts.Account" />

           </callout>

</callout.config>


 

Well, I modified the code and set some attribute of the account to something just to make sure it worked. It did.

How to create a site in SharePoint from one server? Well, first I tried adding Microsoft.SharePoint.dll which contains lots of nice stuff to access the SharePoint data. This was the technique I had used previously and thought it might be good this time too. But no, it can actually only be used on the same server as SharePoint and not on some other server.

There are still a lot of nice web services in SharePoint, I could probably find some web method that would let me create my site. I started by looking in the WssSDK…

But I could find anything useful. The natural webservice would of course be webs.asmx and it contains lot of nice functions to handle SharePoint webs, like GetWeb() and so on. But I found no way of creating a new site. In the admin.asmx I found a method called createSite() but that creates sitecollections which is not really what I wanted. (Each sitecollection has unique security handling, template and sitedefinition setup and a lot of other specific stuff) My customer has around 5000 customer and I would want to create 5000 sitecollections.

I started searching the Internet. But, no. All I could find was a blog entry by Nick Swan describing how to use admin.createSite() (http://weblog.vb-tech.com/nick/archive/2006/03/07/1472.aspx).

I contacted Pontus Haglund and Kalle Becker at Microsoft and my colleague Sebastian Tegel and asked them if they knew how to do this or could assist in any way. They didn't unfortunately.  

I was left with only one major option as I saw it; creating my own web service that used Microsoft.SharePoint.dll functions to create the web site (subweb). I had found a blog that described how to do this (http://blogs.ittoolbox.com/km/sharepoint/archives/creating-a-custom-web-service-for-sharepoint-13553). So, I thought that it shouldn't be that big of a hazel. To make sure my SharePointcode worked, I first created a normal windows forms application that created a site according to certain variables. I found that the following code worked very well:


 


string url = "";

SPSecurity.RunWithElevatedPrivileges(delegate()

{

SPSite siteCollection = new SPSite("http://intranet");

SPWebCollection subSites = siteCollection.AllWebs["customersites"].Webs;


 

SPWebTemplateCollection templates = siteCollection.GetCustomWebTemplates(1033);

SPWebTemplate template = templates[0];


 

SPWeb mySite = subSites.Add(name, Title, Description, 1033, template, false, false);

mySite.Update();

url = mySite.Url;

});


return url;


 

After a suggestion from my colleague Sebastian Tegel, I ran all the code with Elevated Privileges. Not sure it is actually needed but I added it to make sure that there isn't any security issues with the current user and permissions to create sites.

Now, I just had to follow the blog I had found. Again my misfortune struck me, as I was unable to make any sense of it. I got the web service to work as long as I didn't use any SharePoint functions. When I did, I got the following error:

System.IO.FileNotFoundException: The Web application at http://intranet could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.

   at Microsoft.SharePoint.SPSite..ctor(SPFarm farm, Uri requestUri, Boolean contextSite, SPUserToken userToken)

.

.

.


 

I was using the exact same code as I had tested in the forms test application so there wasn't any problems there.

The blog post mentions a lot about strong naming assemblies but it doesn't reference it with the strong name and my experience told me that this error probably was due to Code Access Security (CAS) problems. The assembly should be strong-named, placed in the GAC and referenced using the strong name.

I think some important pictures has fallen out of the blog why it doesn't make much sense. It did however mention that there was a walk-through on msdn that described the same thing. This was my next lead on the way to my goal of SharePoint document handling In MS CRM 3.

I found the walk-through (http://msdn2.microsoft.com/en-us/library/ms464040.aspx) and followed it minutely. It gave me a lot better feeling than the first blog posting I had found. In short, it described how to create a web service asmx-file that references a strong named assembly with a class of web methods in it. When created, the program disco.exe was used to create wsdl and disco files for the web service. When these had been created, the were renamed to become aspx files so that they can dynamically link to the webservice depending on where in SharePoint it has been referenced. (all sharepoint webservices can be found in the sub directory of /_vti_bin/ of any site, for instance the web service webs.asmx can be found in both the url http://intranet/_vti_bin/webs.asmx and http://intranet/customersites/webs.asmx). When the wsdl and disco files have been properly modified to fit the SharePoint standard of handling this feature, the new web service has to be added to the file spdisco.aspx which is a directory of all web services that are available.

After a lot of hazel, I got this to work, and with a strong named assembly, deployed in the GAC and run in the SharePoint context. I finally got it to work the way I wanted it to.

So, if you also want your own web service in SharePoint. I would suggest following the walk-through very thoroughly and I have a few pointers. My web service was called WebsExtra.asmx, my class was called Service, and the assembly "WSTools.dll".

  1. First, make sure the asmx-file works. Develop it using a normal web application. You should be able to address it. I had created a new web site using TCP port 8000 and hence tried: http://intranet:8000/WebsExtra.asmx. If that doesn't work, make sure you have strong named your assembly correctly, deployed it the the GAC (i.e. copied it to c:\windows\assembly) and addressed the class using the full strong name ("Service, WSTools, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=037c5a828198ba1e" in my case).
  2. Ok. That works. Good. Make sure the file also works when you placed it in the _layouts directory according to the walk-through. If not, you might still not be addressing the class with the full strong name.
  3. After I created the files WebsExtra.wsdl and WebsExtra.disco, copied them to the ISAPI directory, renamed them to WebsExtrawsdl.aspx and WebsExtradisco.aspx, and modified them to be able to handle the dynamic linking that SharePoint uses, I made sure that I could really see the aspx-files using IE. I found them at http://intranet/_vti_bin/WebsExtrawsdl.aspx and http://intranet/_vti_bin/WebsExtradisco.aspx .
    Also check the contents of them and make sure they follow the same structure as similar files in the ISAPI directory (for instance Webswsdl.aspx and Websdisco.aspx, which you also can find using IE). Make sure that the referencing to the web service really uses the name you have set and not the name used in the walk-through.At the bottom of this entry is a copy of the files I used and a copy of the result I got in IE.
  4. When both these files work, make the additions to the bottom of spdisco.aspx as well (within the discovery-tag though). This file can also be found using IE. You can probably guess it's url. Have a look at my version at the bottom of this entry, including the result in IE.
  5. When I got that working, I now tried to access the addresses:
    http://intranet/_vti_bin/WebsExtra.asmx?wsdl and http://intranet/_vti_bin/WebsExtra.disco. These aren't actually files that you can find in the ISAPI directory but are mapped to the aspx-files mentioned in 3 above. You can check this by checking one of the out-of-the-box web services like Webs.asmx.
  6. When you've got all these working properly, you should be able to add the web service as a web reference in some test project. (I usually use Windows Forms programs since they are the easiest to debug). If all has been set up properly, you should now be able to add the web service as a web refence. If the dialog gives you problems, it is usually due to errors in the wsdl or disco files. I had lots of these and was quite close to suicide but finally found them all. Most of the problems I had were due to the fact that I had used Visual Studio to edit the wsdl and disco aspx files. VS 2005 had been very "helpful" and had added ="" here and there, making the syntax erroneous. So, my suggestion, use notepad to copy paste the code from the walk-through. When that is done, you can use VS 2005 to modify the code.


     

WebsExtrawsdl.aspx

<%@
Page
Language="C#"
Inherits="System.Web.UI.Page"
%>

<%@
Assembly
Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
%>

<%@
Import
Namespace="Microsoft.SharePoint.Utilities"
%>

<%@
Import
Namespace="Microsoft.SharePoint"
%>

<% Response.ContentType = "text/xml"; %>

<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://tempuri.org/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
targetNamespace="http://tempuri.org/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">


<wsdl:types>


<s:schema
elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">


<s:element
name="CreateSharePointSubWeb">


<s:complexType>


<s:sequence>


<s:element
minOccurs="0"
maxOccurs="1"
name="portalUrl"
type="s:string"
/>


<s:element
minOccurs="0"
maxOccurs="1"
name="subsite"
type="s:string"
/>


<s:element
minOccurs="0"
maxOccurs="1"
name="name"
type="s:string"
/>


<s:element
minOccurs="0"
maxOccurs="1"
name="Title"
type="s:string"
/>


<s:element
minOccurs="0"
maxOccurs="1"
name="Description"
type="s:string"
/>


<s:element
minOccurs="1"
maxOccurs="1"
name="templateId"
type="s:int"
/>


</s:sequence>


</s:complexType>


</s:element>


<s:element
name="CreateSharePointSubWebResponse">


<s:complexType>


<s:sequence>


<s:element
minOccurs="0"
maxOccurs="1"
name="CreateSharePointSubWebResult"
type="s:string"
/>


</s:sequence>


</s:complexType>


</s:element>


<s:element
name="HelloWorld">


<s:complexType
/>


</s:element>


<s:element
name="HelloWorldResponse">


<s:complexType>


<s:sequence>


<s:element
minOccurs="0"
maxOccurs="1"
name="HelloWorldResult"
type="s:string"
/>


</s:sequence>


</s:complexType>


</s:element>


</s:schema>


</wsdl:types>


<wsdl:message
name="CreateSharePointSubWebSoapIn">


<wsdl:part
name="parameters"
element="tns:CreateSharePointSubWeb"
/>


</wsdl:message>


<wsdl:message
name="CreateSharePointSubWebSoapOut">


<wsdl:part
name="parameters"
element="tns:CreateSharePointSubWebResponse"
/>


</wsdl:message>


<wsdl:message
name="HelloWorldSoapIn">


<wsdl:part
name="parameters"
element="tns:HelloWorld"
/>


</wsdl:message>


<wsdl:message
name="HelloWorldSoapOut">


<wsdl:part
name="parameters"
element="tns:HelloWorldResponse"
/>


</wsdl:message>


<wsdl:portType
name="ServiceSoap">


<wsdl:operation
name="CreateSharePointSubWeb">


<wsdl:input
message="tns:CreateSharePointSubWebSoapIn"
/>


<wsdl:output
message="tns:CreateSharePointSubWebSoapOut"
/>


</wsdl:operation>


<wsdl:operation
name="HelloWorld">


<wsdl:input
message="tns:HelloWorldSoapIn"
/>


<wsdl:output
message="tns:HelloWorldSoapOut"
/>


</wsdl:operation>


</wsdl:portType>


<wsdl:binding
name="ServiceSoap"
type="tns:ServiceSoap">


<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
/>


<wsdl:operation
name="CreateSharePointSubWeb">


<soap:operation
soapAction="http://tempuri.org/CreateSharePointSubWeb"
style="document"
/>


<wsdl:input>


<soap:body
use="literal"
/>


</wsdl:input>


<wsdl:output>


<soap:body
use="literal"
/>


</wsdl:output>


</wsdl:operation>


<wsdl:operation
name="HelloWorld">


<soap:operation
soapAction="http://tempuri.org/HelloWorld"
style="document"
/>


<wsdl:input>


<soap:body
use="literal"
/>


</wsdl:input>


<wsdl:output>


<soap:body
use="literal"
/>


</wsdl:output>


</wsdl:operation>


</wsdl:binding>


<wsdl:binding
name="ServiceSoap12"
type="tns:ServiceSoap">


<soap12:binding
transport="http://schemas.xmlsoap.org/soap/http"
/>


<wsdl:operation
name="CreateSharePointSubWeb">


<soap12:operation
soapAction="http://tempuri.org/CreateSharePointSubWeb"
style="document"
/>


<wsdl:input>


<soap12:body
use="literal"
/>


</wsdl:input>


<wsdl:output>


<soap12:body
use="literal"
/>


</wsdl:output>


</wsdl:operation>


<wsdl:operation
name="HelloWorld">


<soap12:operation
soapAction="http://tempuri.org/HelloWorld"
style="document"
/>


<wsdl:input>


<soap12:body
use="literal"
/>


</wsdl:input>


<wsdl:output>


<soap12:body
use="literal"
/>


</wsdl:output>


</wsdl:operation>


</wsdl:binding>


<wsdl:service
name="Service">


<wsdl:port
name="ServiceSoap"
binding="tns:ServiceSoap">


<soap:address
location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>
/>


</wsdl:port>


<wsdl:port
name="ServiceSoap12"
binding="tns:ServiceSoap12">


<soap12:address
location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>
/>


</wsdl:port>


</wsdl:service>

</wsdl:definitions>


 

When accessed at http://intranet/_vti_bin/WebsExtrawsdl.aspx or http://intranet/_vti_bin/WebsExtra.asmx?wsdl the following was the result:


 

<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://tempuri.org/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
targetNamespace="http://tempuri.org/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

    <wsdl:types>

        <s:schema
elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">

            <s:element
name="CreateSharePointSubWeb">

                <s:complexType>

                    <s:sequence>

                        <s:element
minOccurs="0"
maxOccurs="1"
name="portalUrl"
type="s:string" />

                        <s:element
minOccurs="0"
maxOccurs="1"
name="subsite"
type="s:string" />

                        <s:element
minOccurs="0"
maxOccurs="1"
name="name"
type="s:string" />

                        <s:element
minOccurs="0"
maxOccurs="1"
name="Title"
type="s:string" />

                        <s:element
minOccurs="0"
maxOccurs="1"
name="Description"
type="s:string" />

                        <s:element
minOccurs="1"
maxOccurs="1"
name="templateId"
type="s:int" />

                    </s:sequence>

                </s:complexType>

            </s:element>

            <s:element
name="CreateSharePointSubWebResponse">

                <s:complexType>

                    <s:sequence>

                        <s:element
minOccurs="0"
maxOccurs="1"
name="CreateSharePointSubWebResult"
type="s:string" />

                    </s:sequence>

                </s:complexType>

            </s:element>

            <s:element
name="HelloWorld">

                <s:complexType />

            </s:element>

            <s:element
name="HelloWorldResponse">

                <s:complexType>

                    <s:sequence>

                        <s:element
minOccurs="0"
maxOccurs="1"
name="HelloWorldResult"
type="s:string" />

                    </s:sequence>

                </s:complexType>

            </s:element>

        </s:schema>

    </wsdl:types>

    <wsdl:message
name="CreateSharePointSubWebSoapIn">

        <wsdl:part
name="parameters"
element="tns:CreateSharePointSubWeb" />

    </wsdl:message>

    <wsdl:message
name="CreateSharePointSubWebSoapOut">

        <wsdl:part
name="parameters"
element="tns:CreateSharePointSubWebResponse" />

    </wsdl:message>

    <wsdl:message
name="HelloWorldSoapIn">

        <wsdl:part
name="parameters"
element="tns:HelloWorld" />

    </wsdl:message>

    <wsdl:message
name="HelloWorldSoapOut">

        <wsdl:part
name="parameters"
element="tns:HelloWorldResponse" />

    </wsdl:message>

    <wsdl:portType
name="ServiceSoap">

        <wsdl:operation
name="CreateSharePointSubWeb">

            <wsdl:input
message="tns:CreateSharePointSubWebSoapIn" />

            <wsdl:output
message="tns:CreateSharePointSubWebSoapOut" />

        </wsdl:operation>

        <wsdl:operation
name="HelloWorld">

            <wsdl:input
message="tns:HelloWorldSoapIn" />

            <wsdl:output
message="tns:HelloWorldSoapOut" />

        </wsdl:operation>

    </wsdl:portType>

    <wsdl:binding
name="ServiceSoap"
type="tns:ServiceSoap">

        <soap:binding
transport="http://schemas.xmlsoap.org/soap/http" />

        <wsdl:operation
name="CreateSharePointSubWeb">

            <soap:operation
soapAction="http://tempuri.org/CreateSharePointSubWeb"
style="document" />

            <wsdl:input>

                <soap:body
use="literal" />

            </wsdl:input>

            <wsdl:output>

                <soap:body
use="literal" />

            </wsdl:output>

        </wsdl:operation>

        <wsdl:operation
name="HelloWorld">

            <soap:operation
soapAction="http://tempuri.org/HelloWorld"
style="document" />

            <wsdl:input>

                <soap:body
use="literal" />

            </wsdl:input>

            <wsdl:output>

                <soap:body
use="literal" />

            </wsdl:output>

        </wsdl:operation>

    </wsdl:binding>

    <wsdl:binding
name="ServiceSoap12"
type="tns:ServiceSoap">

        <soap12:binding
transport="http://schemas.xmlsoap.org/soap/http" />

        <wsdl:operation
name="CreateSharePointSubWeb">

            <soap12:operation
soapAction="http://tempuri.org/CreateSharePointSubWeb"
style="document" />

            <wsdl:input>

                <soap12:body
use="literal" />

            </wsdl:input>

            <wsdl:output>

                <soap12:body
use="literal" />

            </wsdl:output>

        </wsdl:operation>

        <wsdl:operation
name="HelloWorld">

            <soap12:operation
soapAction="http://tempuri.org/HelloWorld"
style="document" />

            <wsdl:input>

                <soap12:body
use="literal" />

            </wsdl:input>

            <wsdl:output>

                <soap12:body
use="literal" />

            </wsdl:output>

        </wsdl:operation>

    </wsdl:binding>

    <wsdl:service
name="Service">

        <wsdl:port
name="ServiceSoap"
binding="tns:ServiceSoap">

            <soap:address
location="http://intranet/_vti_bin/WebsExtrawsdl.aspx" />

        </wsdl:port>

        <wsdl:port
name="ServiceSoap12"
binding="tns:ServiceSoap12">

            <soap12:address
location="http://intranet/_vti_bin/WebsExtrawsdl.aspx" />

        </wsdl:port>

    </wsdl:service>

</wsdl:definitions>


 

And the file WebsExtradisco.aspx:

<%@
Page
Language="C#"
Inherits="System.Web.UI.Page"
%>
<%@
Assembly
Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
%>
<%@
Import
Namespace="Microsoft.SharePoint.Utilities"
%>
<%@
Import
Namespace="Microsoft.SharePoint"
%>

<% Response.ContentType = "text/xml"; %>

<discovery
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/disco/">


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request) + "?wsdl"),Response.Output); %>
docref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<soap
address=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>
xmlns:q1="http://tempuri.org/"
binding="q1:ServiceSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/"
/>


<soap
address=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>
xmlns:q2="http://tempuri.org/"
binding="q2:ServiceSoap12"
xmlns="http://schemas.xmlsoap.org/disco/soap/"
/>

</discovery>


 

And when I browsed the pages http://intranet/_vti_bin/WebsExtradisco.aspx or http://intranet/_vti_bin/WebsExtra.disco was:


 

<discovery
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/disco/">

    <contractRef
ref="http://intranet/_vti_bin/WebsExtradisco.aspx?wsdl"
docref="http://intranet/_vti_bin/WebsExtradisco.aspx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <soap
address="http://intranet/_vti_bin/WebsExtradisco.aspx"
xmlns:q1="http://tempuri.org/"
binding="q1:ServiceSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/" />

    <soap
address="http://intranet/_vti_bin/WebsExtradisco.aspx"
xmlns:q2="http://tempuri.org/"
binding="q2:ServiceSoap12"
xmlns="http://schemas.xmlsoap.org/disco/soap/" />

</discovery>


 

Of course, to make the address translation from http://intranet/_vti_bin/WebsExtra.disco actually point to the correct file http://intranet/_vti_bin/WebsExtradisco.aspx and similary http://intranet/_vti_bin/WebsExtra.asmx?wsdl point to http://intranet/_vti_bin/WebsExtrawsdl.aspx the correct setting have to be added to the file spdisco.aspx. This is the version I had (Notice the two last tags before the if-statement):


 

<%@
Page
Language="C#"
Inherits="System.Web.UI.Page"
%>
<%@
Assembly
Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
%>
<%@
Import
Namespace="Microsoft.SharePoint.Utilities"
%>
<%@
Import
Namespace="Microsoft.SharePoint"
%>

<%@
Import
Namespace="Microsoft.SharePoint.WebControls"
%>

<%@
Import
Namespace="Microsoft.SharePoint.Administration"
%>

<% SPSite spServer = SPControl.GetContextSite(Context); SPWeb spWeb = SPControl.GetContextWeb(Context); %>

<% Response.ContentType = "text/xml"; %>

<discovery
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.xmlsoap.org/disco/">


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/alerts.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/alerts.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/alerts.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/Authentication.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/Authentication.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/Authentication.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/copy.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/copy.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/copy.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/dspsts.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/dspsts.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/dspsts.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/dws.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/dws.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/dws.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/forms.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/forms.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/forms.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/imaging.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/imaging.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/imaging.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/lists.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/lists.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/lists.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/meetings.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/meetings.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/meetings.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/People.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/People.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/People.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/permissions.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/permissions.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/permissions.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/SharepointEmailWS.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/SharepointEmailWS.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/SharepointEmailWS.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/SiteData.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/SiteData.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/SiteData.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/sites.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/sites.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/sites.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/spsearch.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/spsearch.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/spsearch.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/UserGroup.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/UserGroup.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/UserGroup.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/versions.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/versions.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/versions.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/views.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/views.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/views.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/WebPartPages.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/WebPartPages.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/WebPartPages.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/webs.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/webs.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/webs.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>


<contractRef
ref=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/WebsExtra.asmx?wsdl", '"'); %>
docRef=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/WebsExtra.asmx", '"');%>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<soap
address=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/WebsExtra.asmx", '"'); %>
xmlns:q1="http://schemas.microsoft.com/sharepoint/soap/directory/"
binding="q1:ServiceSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/"
/>

<%

    if (spServer.WebApplication is SPAdministrationWebApplication)

    {

%>


<contractRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_adm/Admin.asmx?wsdl"),Response.Output); %>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_adm/Admin.asmx"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/scl/"
/>


<discoveryRef
ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_adm/Admin.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/"
/>

<% } %>

</discovery>


 

And when browsing to http://intranet/_vti_bin/spdisco.aspx I got the following result:

<discovery
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/disco/">

    <contractRef
ref="http://intranet/_vti_bin/WebsExtradisco.aspx?wsdl"
docref="http://intranet/_vti_bin/WebsExtradisco.aspx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <soap
address="http://intranet/_vti_bin/WebsExtradisco.aspx"
xmlns:q1="http://tempuri.org/"
binding="q1:ServiceSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/" />

    <soap
address="http://intranet/_vti_bin/WebsExtradisco.aspx"
xmlns:q2="http://tempuri.org/"
binding="q2:ServiceSoap12"
xmlns="http://schemas.xmlsoap.org/disco/soap/" />

</discovery>

<discovery
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.xmlsoap.org/disco/">

    <contractRef
ref="http://intranet/_vti_bin/alerts.asmx?wsdl"
docRef="http://intranet/_vti_bin/alerts.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/alerts.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/Authentication.asmx?wsdl"
docRef="http://intranet/_vti_bin/Authentication.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/Authentication.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/copy.asmx?wsdl"
docRef="http://intranet/_vti_bin/copy.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/copy.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/dspsts.asmx?wsdl"
docRef="http://intranet/_vti_bin/dspsts.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/dspsts.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/dws.asmx?wsdl"
docRef="http://intranet/_vti_bin/dws.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/dws.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/forms.asmx?wsdl"
docRef="http://intranet/_vti_bin/forms.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/forms.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/imaging.asmx?wsdl"
docRef="http://intranet/_vti_bin/imaging.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/imaging.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/lists.asmx?wsdl"
docRef="http://intranet/_vti_bin/lists.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/lists.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/meetings.asmx?wsdl"
docRef="http://intranet/_vti_bin/meetings.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/meetings.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/People.asmx?wsdl"
docRef="http://intranet/_vti_bin/People.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/People.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/permissions.asmx?wsdl"
docRef="http://intranet/_vti_bin/permissions.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/permissions.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/SharepointEmailWS.asmx?wsdl"
docRef="http://intranet/_vti_bin/SharepointEmailWS.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/SharepointEmailWS.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/SiteData.asmx?wsdl"
docRef="http://intranet/_vti_bin/SiteData.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/SiteData.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/sites.asmx?wsdl"
docRef="http://intranet/_vti_bin/sites.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/sites.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/spsearch.asmx?wsdl"
docRef="http://intranet/_vti_bin/spsearch.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/spsearch.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/UserGroup.asmx?wsdl"
docRef="http://intranet/_vti_bin/UserGroup.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/UserGroup.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/versions.asmx?wsdl"
docRef="http://intranet/_vti_bin/versions.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/versions.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/views.asmx?wsdl"
docRef="http://intranet/_vti_bin/views.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/views.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/WebPartPages.asmx?wsdl"
docRef="http://intranet/_vti_bin/WebPartPages.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/WebPartPages.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/webs.asmx?wsdl"
docRef="http://intranet/_vti_bin/webs.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <discoveryRef
ref="http://intranet/_vti_bin/webs.asmx?disco"
xmlns="http://schemas.xmlsoap.org/disco/" />

    <contractRef
ref="http://intranet/_vti_bin/WebsExtra.asmx?wsdl"
docRef="http://intranet/_vti_bin/WebsExtra.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />

    <soap
address="http://intranet/_vti_bin/WebsExtra.asmx"
xmlns:q1="http://schemas.microsoft.com/sharepoint/soap/directory/"
binding="q1:ServiceSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/" />

</discovery>


 

So, with these example files, and these tips, I hope I can ease your troubles in making you own custom sharepoint web service.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se


 

Friday, August 10, 2007

Problems with read-only fields...

When creating javascripts in general and when working with AJAX-based javascripts (javascripts that access server based information) specifically, it is not uncommon to update attributes in CRM-forms. If these attributes are “Disabled” using the form-editor or are disabled using javascript in with the following code:

crmForm.all.xxx_myfield.Disabled = true;

Then any updates to the data of this field, will NOT be saved when the form is saved. There is a way to bypass this and this is to set the attribute to “Read only” instead, with the following javascript code:

crmForm.all.xxx_myfield.readOnly = true;

This will disable any editing of the field by the user, but any data that is modified will still be saved.
I have some other stuff I will share with you soon aswell.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Wednesday, August 08, 2007

Inactivating custom entities in code

I am currently working with as a sub consultant for what I beleive is Swedens foremost MS CRM supplier, Cybernetics, and ran into some problems when trying to deactivate a custom entity using code. I was unable to find any documentation at all in the latest version of the SDK but after a little searching, I found that Jonas Deibe at Microsoft Sweden, had the solution. Please have a look if you want to know how to do it:
http://blogs.msdn.com/jonasd/archive/2007/04/04/setting-status-with-setstatedynamicentityrequest.aspx

I'll just give you some code my self:

SetStateDynamicEntityRequest req = new SetStateDynamicEntityRequest();
req.Entity = new Moniker();
req.Entity.Id = yfid;
req.Entity.Name = EntityName.cyb_yearlybusiness.ToString();
req.State = "inactive"; // = Deactivation
req.Status = -1;
service.Execute(req);

I have seen some very interesting "fake lookups" here at Cybernetics aswell, and I will soon be writing about how to create them.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Friday, August 03, 2007

No more vacation - but soon Convergence!

Well, my 7 week vacation/parent leave is coming to an end, as is my low activity on this blog. I've been away from a proper internet connection which is why I havn't been to active. It will be intersting to start working again now, that I have a 7 weeks old daughter at home.

Well, I really like to work with these products and all the interesting customers I have, so it's not very saddening to go back to work, and I like to be active here as well.

In october I hope to be meeting some of you at Convergence 2007 in Copenhagen. It will be some very interesting days. If you havn't registered already, please do, it will be very valuable. Have a look at Microsofts webpage: http://www.microsoft.com/dynamics/convergence/copenhagen/default.aspx

I will be staying at Copenhagen Strand, it would be nice to meet some of my blog readers, so if you havn't already booked an hotel, you could always give it a try. Hope to see you there in person!

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Thursday, July 12, 2007

Interesting fix for anoying problem

As some of you who work with SharePoint might have noticed, when creating a web-part-page-document-library, the new pages loose the quick launch. Patrick Tisseghem has written a blog on why this is and how to fix it using SharePoint Designer.

http://www.u2u.info/Blogs/Patrick/Lists/Posts/Post.aspx?List=91f6455c%2D4448%2D4303%2D8a38%2Db1722e1522d1&ID=1744

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Excel Add-in for double directional sync of SharePointlists with Excel.

As many of you might know, the functionality of double directional syncronization between SharePoint lists and Excel sheets was removed in the 2007 version. Why? I don't know, it probably didn't make the magic features-that-will-be-included-line. However, an add-in for Excel 2007 can now be downloaded that enables this feature.

Check it out: http://www.microsoft.com/downloads/details.aspx?FamilyID=25836e52-1892-4e17-ac08-5df13cfc5295&DisplayLang=en

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Wednesday, June 20, 2007

CRM Diag Tool

Want do check how a CRM installation is? Have a look at CRM Diag Tool at this webpage: http://blogs.msdn.com/benlec/archive/2007/06/06/new-crmdiagtoolturbo-3-0-5300-060607-uploaded-06-06-07.aspx

It helps you analyze a CRM installation. I havn't tried it yet but when I have I will tell you some more. I wrote this post just in case you didn't know it existed (like me).

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Sunday, June 17, 2007

CRM with MapPoint

Integrating a map service into MS CRM with mesh-up technology is not very hard and can add very strong functionality to the users/customer. I havn't worked in a project yet that wanted this functionality which is the reason why I havn't blogged about it.

However, today I had a look at the CRM Team blog and found that Ayaz Ahmad, a CRM MVP has written a blog entry on how to make a simple CRM integration with Microsoft Mappoint.

Please have a look here if you are interested:
http://blogs.msdn.com/crm/archive/2007/06/14/microsoft-dynamics-crm-and-mappoint-integration-a-picture-is-worth-a-thousand-words.aspx

I am not sure how well MapPoint works in Europe/Northern Europe but I don't think integration with Google Earth (sorry MS, I know you hate them :) or other similar services (www.hitta.se, www.eniro.se) is very much harder as long as the do have a wsdl-webservice that can easily be consumed, or can easily be configured using URL-parameters.

Anyway, start off with MapPoint, if it doesn't go all the way for you, try working with some other Map Service supplier. There might also be some nice ActiveX-based map-service if a better map GUI is needed.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

New CRM VPC

Well, my daughter is sleeping so I have some time to blog a bit and read some other blogs.

The so-called May-VPC containing a CRM Demo environment will soon be out-dated and a couple of guys are working on a new environment. It will contain SharePoint 2007, VS 2005 and a lot more which is good news, since it therefore can be used for demos, education and simple development projects (larger development projects should be based on an empty CRM, with some customer specific data). I am looking forward to it! Read a bit more about it on Mennotk's blog: http://blogs.msdn.com/mscrmfreak/archive/2007/06/12/new-microsoft-dynamics-crm-vpc-update.aspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Friday, June 15, 2007

Off topic: I am now a father!

17:03 on the 12:th of june, my wife gave birth to my first child, a beautiful little girl! She has been named Liv Nora Hogseth Westerlund, Nora being her primary name.

So, if you find this blog to be a bit slow the next few weeks, please have a look at the pictures at my private website www.westerlund.info, and you will understand why this is so.

Gustaf Westerlund
Father & CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Monday, June 11, 2007

How to customize search in SharePoint

Patrick Tissegheim, a very competent SharePoint MVP at U2U has made a very good video presentation of how to customize search in SharePoint. He works with the tabbed searching and shows how to create your own search page, search result page and how to use SharePoint Designer GUI to create the XSLT used to show the result of a search. Very nice, if you havn't seen it, you should.

http://msdn2.microsoft.com/en-us/library/bb428855.aspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

SharePoint links

Looking for some good links to SharePoint related material, have a look bellow:

SharePoint whitepapers:
http://www.combined-knowledge.com/Downloads%202007.htm

Office SharePoint Server 2007 on TechNet
http://technet2.microsoft.com/Office/en-us/library/5233cf43-6a8f-40cb-9014-0724600e7e381033.mspx?mfr=true

Microsoft Office Systems for Architects
http://msdn2.microsoft.com/sv-se/architecture/aa699381.aspx

Application Templates
http://www.microsoft.com/technet/windowsserver/sharepoint/wssapps/templates/datasheets.mspx

I will publish more when I find anything useful!


Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Dynamics on MSDN

Dynamics (the product family of which CRM is part), now has it's own corner in MSDN. Please have a look:
http://msdn2.microsoft.com/en-us/dynamics/default.aspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Tuesday, June 05, 2007

Reports.config has invalid schema

I was working with setting up a demo/lab environment with SQL 2005, MOSS Ent 2007 and MS CRM 3, Office 2007 Ultimate.

However, I had problems getting the reports to work, when trying to access the reportpage, I got the error: "Reports.config has invalid schema".

I looked around a bit on the net and found that one of the blogs I suibscribe to actually discussed the problem at hand.

http://blogs.msdn.com/mscrmfreak/archive/2006/05/17/599371.aspx

It seemed that the reason for the error was that .NET 2.0 had been defaultet for the CRM 3 website (and we all know it is .NET 1.1, right!). So, tried to run "aspnet_regiis -r" as described but I got the same error as the comment by "Matt Thomas", my CRM just stopped working.

So, what to do. I found that when you run "aspnet_regiis -r" it resetts all websites to the version of .NET that you run it from (ex. C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_regiis -r, will set all websites to use .NET 1.1). This is not desirable since my MOSS 2007, SQL 2005 RS and all MOSS admin sites (central admin, my site, SSP) all should run .NET 2.0. So, I thought it better to reset all sites to .NET 2.0 and then manually set the CRM site to 1.1. And so I did, and CRM just stalled when loading. No error message, no nothn'!

This got me thinking that you should be able to run one version of aspnet_regiis for just one website. So, by trying the all-usefull "/?" parameter I found that using "aspnet_regiis -lk" will list all different IIS-paths and show which version they were running. This was what I found:
C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322>aspnet_regiis -lk
W3SVC/ 2.0.50727.42W3SVC/1/ROOT/ 2.0.50727.42
W3SVC/1/ROOT/_layouts/images/ 2.0.50727.42
W3SVC/1/ROOT/_layouts/inc/ 2.0.50727.42
W3SVC/131316714/root/ 2.0.50727.42
W3SVC/131316714/root/Reports/ 2.0.50727.42
W3SVC/131316714/root/ReportServer/ 2.0.50727.42
W3SVC/1720207907/root/ 2.0.50727.42
W3SVC/2/ROOT/ 1.1.4322.0
W3SVC/2/ROOT/MSCRMServices/ 2.0.50727.42
W3SVC/2075257487/Root/ 2.0.50727.42
W3SVC/2075257487/Root/_layouts/images/ 2.0.50727.42
W3SVC/2075257487/Root/_layouts/inc/ 2.0.50727.42
W3SVC/425288717/Root/ 2.0.50727.42
W3SVC/425288717/Root/_layouts/images/ 2.0.50727.42
W3SVC/425288717/Root/_layouts/inc/ 2.0.50727.42
W3SVC/493651791/Root/ 2.0.50727.42
W3SVC/493651791/Root/_layouts/images/ 2.0.50727.42
W3SVC/493651791/Root/_layouts/inc/ 2.0.50727.42

Aha! Can you see what is wrong? Well, when I manually set CRM to .NET 1.1 it didn't do that recursivly! The CRM webservice is running as a separate application, and I hadn't changed that. This is the row that shows what's wrong:

W3SVC/2/ROOT/MSCRMServices/ 2.0.50727.42

So, I checked what parameters you could use with aspnet_regiis and found that "-s " seemed like a good idea. Hence, I ran:

aspnet_regiis -s W3SVC/2/ROOT

I think it might just have worked with going in to the CRM site and changing it for the MSCRMService virtual directory, but I thought it better to set it to the entire MS CRM 3 website recursivly to make sure everything was ok. When it had completed (takes a minute or two), I ran "aspnet_regiis -lk" again to check the current status:

W3SVC/ 2.0.50727.42W3SVC/1/ROOT/ 2.0.50727.42
W3SVC/1/ROOT/_layouts/images/ 2.0.50727.42
W3SVC/1/ROOT/_layouts/inc/ 2.0.50727.42
W3SVC/131316714/root/ 2.0.50727.42
W3SVC/131316714/root/Reports/ 2.0.50727.42
W3SVC/131316714/root/ReportServer/ 2.0.50727.42
W3SVC/1720207907/root/ 2.0.50727.42
W3SVC/2/ROOT/ 1.1.4322.0
W3SVC/2/ROOT/MSCRMServices/ 1.1.4322.0
W3SVC/2075257487/Root/ 2.0.50727.42
W3SVC/2075257487/Root/_layouts/images/ 2.0.50727.42
W3SVC/2075257487/Root/_layouts/inc/ 2.0.50727.42
W3SVC/425288717/Root/ 2.0.50727.42
W3SVC/425288717/Root/_layouts/images/ 2.0.50727.42
W3SVC/425288717/Root/_layouts/inc/ 2.0.50727.42
W3SVC/493651791/Root/ 2.0.50727.42
W3SVC/493651791/Root/_layouts/images/ 2.0.50727.42
W3SVC/493651791/Root/_layouts/inc/ 2.0.50727.42

As you can see, the MSCRMService is now also .NET 1.1.

After this I restarted the IIS with "iisreset", and tried to run CRM and the reports;
Everything worked as it should!

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

SQL Server 2008

Microsoft are planning to release a new version of SQL Server next year that will be called Microsoft SQL Server 2008.

It hosts lots of new features, for instance the ability to work directly with entities in the database instead of tables and views. An interesting feature, I wonder how good it will be.

SQL Reports will also be better and the integration with MS Office system (=SharePoint?) has be enhanced.

Have a look at Microsofts website for SQL Server 2008 for more information and some videos.

http://www.microsoft.com/sql/prodinfo/futureversion/default.mspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Saturday, June 02, 2007

MOM Pack

Microsoft Operations Management (or similar programs) is a program that every serious IT-department runns to make sure all servers, clients and applications run as they should. Microsoft has release a MOM-pack for CRM so, if you want to monitor what CRM is or isn't doing, I suggest you have a look at it!

http://blogs.msdn.com/crm/archive/2007/06/01/released-microsoft-dynamics-crm-3-server-management-pack-for-mom-2005.aspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Friday, June 01, 2007

Backup of SharePoint

Backing up SharePoint is not just backing up the databases and hoping for the best. Best Practice is actually using the tool stsadm and create backupfiles that can be then be backed up to tape (or similar). So, how to create a script that takes backup?

Example of script for catastrophic backup:
@echo offecho start Catastrophic backup >> backup.log
date /t >> backup.log
time /t >> backup.log
"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\stsadm" -o backup -directory \\srv01\Backup\CatastrophicBackup -backupmethod full >> backup.log
date /t >> backup.log
time /t >> backup.log
echo end Catastropic backup >> backup.log

This will create a new folder in the directory \\srv01\Backup\CatastrophicBackup where backup of all databases will be done.

However, the problem with this is that you can't restore just one file... so what to do?
Two alternatives:
1. Just export all site data to file using "stsadm -o export", and when needed, restore to secondary sharepoint (not public) and retrieve file.
2. Use 3:rd party backup solution like DocAve 4.1 by AvePoint that has single-item-restore.

An example of how to uses stsadm for creating a normal export is:

stsadm -o export -url http://portal -filename "\\srv1\Backup\portal.bak" -version 4

This will export everything from http://portal to \\srv1\backup\portal.bak including all versions of all files. Please note that if you have lots of data, it might take som time to do this.

Note that there is also a version of "stsadm -o backup" that backs up entire sitecollections but for "simpler" backup set ups I don't find that necessary.

Also note that this is how you handle backup for smaller installations where you can acctually run an export of all data each night. For larger installations, more complex backup methods based on incremental backup or snapshotting can be used.

Since we're using sharepoint for backing up, we don't really have any need for maintaining transactionlogs in SQL server som make sure you have selected "Simple Recovery Model" for each SharePoint database.

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

CRM BizTalk Adaptor - How To

As you might be aware, there is a BizTalk Adaptor for Microsoft CRM 3. I havn't spoken to anyone who has tried it but I just found a nice blog that describes a lot about how to set it up. It is focused for BizTalk experts, but can be very helpful to get a BizTalk CRM integration project started. Have a look and judge for your self:
http://blogs.msdn.com/brajens/archive/2007/05/27/using-microsoft-biztalk-dynamics-crm-adapter-part-1.aspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se

Wednesday, May 30, 2007

Showing related forms

One thing I appreciate about good blogs is the viral spreading of interesting stuff, so that good solutions arn't just available in some corner of the world, but can be used all over. I believe this is one of the real assets of working with the great products MS CRM and MS SharePoint.

I try to keep track of quite a few different blogs and when I find something interesting I (as you have seen before) usually add a posting linking to this blog. This way, I hope you will find my blog even more usefull since you shouldn't really need to keep track of all blogs yourself. (if your interests match mine, that is of course)

On one of the blogs I subscribe to, I found an interesting post concerning how to add related forms into existing forms in MS CRM. This can be very usefull when customers demand GUI modification. So, please have a look: http://blogs.msdn.com/mscrmfreak/archive/2007/05/30/ui-customizations-on-your-coffee-break.aspx

Gustaf Westerlund
CRM and SharePoint Consultant

Humandata AB
www.humandata.se