Thursday, March 5, 2015

Calling a WCF Web Service over HTTPS (SSL)

I was recently trying to access a web service that I wanted to secure over HTTPS. I got it working as an HTTP service, as you do, and made sure that I had a certificate on the server and enabled the https protocol.
I was using basic Http binding and here are the changes that need to be made

          <security mode="Transport">
            <transport clientCredentialType="None" />

That now worked in the browser if I prefixed the url with https://

Next step was that I needed to call the web service where I was not able to access a web.config or an app.config.  Without the service reference being available you have to do this in code. First thing is to make sure you have a copy of the interface class accessible in the client.  It doesn't need to be the same name but it does need to specify the operation contract exactly.

    [ServiceContract]
    public interface IFormDefinition
    {
        [OperationContract]
        [FaultContract(typeof(CRMSoapFault))]
        void PublishFormMetaData(string crmEndPoint, string formId, string webResource, string token);
    }
    [DataContract]
    public class CRMSoapFault
    {
        public CRMSoapFault(string errorMsg)
        {
            this.ErrorMsg = errorMsg;
        }
        ///
        /// This property is used to pass the custom error information
        /// from service to client.
        ///

        [DataMember]
        public string ErrorMsg { get; set; }
    }

To call the web service and set the binding information through code to match this you need to add:

 BasicHttpBinding myBinding = new BasicHttpBinding();
            myBinding.Security.Mode = BasicHttpSecurityMode.Transport;
            myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            EndpointAddress myEndpoint = new EndpointAddress(endPointUrl);
            ChannelFactory myChannelFactory = new ChannelFactory(myBinding, myEndpoint);
            try
            {
                IFormDefinition wcfClient1 = myChannelFactory.CreateChannel();
                // call the web service method
                wcfClient1.PublishFormMetaData(crmEndPoint, formId, webResource, token);

            }
            catch(FaultException faultEx)
            {

             }

Monday, March 2, 2015

Accessing SharePoint Online with Web Client

Misleading title really because if you try and access SharePoint Online using the WebClient it will fail to authenticate.  What you need to do is use the CookieContainer and SharePointOnlineCredentials. 
I got the basics of this from this post. and also from this post which uses a class inherits from WebClient. It mentions that you need the SharePoint Client Components SDK which will install Microsoft.SharePoint.Client.DLL and Microsoft.SharePoint.Client.RunTime.DLL. Add references to both DLLs in your project and add these two using statements

using Microsoft.SharePoint.Client;
using System.Security;


 
Add this class to your project
 
public class ClaimsWebClient : WebClient
{ private CookieContainer cookieContainer;

public ClaimsWebClient(Uri host, string userName, string password)
 
{

cookieContainer = GetAuthCookies(host, userName, password);

}
 
protected override WebRequest GetWebRequest(Uri address)
{
    WebRequest request = base.GetWebRequest(address);
    if (request is HttpWebRequest)
 
    { 
        (request as HttpWebRequest).CookieContainer = cookieContainer;
   }
  
   return request;
 
}
 
private static CookieContainer GetAuthCookies(Uri webUri, string userName, string password)
{    var securePassword = new SecureString();
    foreach (var c in password) { securePassword.AppendChar(c); }
    var credentials = new SharePointOnlineCredentials(userName, securePassword);
    var authCookie = credentials.GetAuthenticationCookie(webUri);
    var cookieContainer = new CookieContainer();
    cookieContainer.SetCookies(webUri, authCookie);      return cookieContainer;
}

}
 


Then call the ClaimWebClient class in the same way as you would the WebClient.  Note that you do not need to set the credentials because it is done within the ClaimWebClient class.

ClaimsWebClient wc = new ClaimsWebClient(new Uri(sharePointSiteUrl), userName, password);

byte[] response = wc.DownloadData(sourceUrl);
 

Saturday, February 28, 2015

Raising SoapFaults on a Web Service

I have used SoapFaults (FaultExceptions) on Web Services before so here is  quick recap. In your Interface class add this declaration

[DataContract]
public class SPSoapFault
{
   public SPSoapFault(string errorMsg)
   {
       this.ErrorMsg = errorMsg;
   }
   [DataMember]
    public string ErrorMsg { get; set; }
}

Beneath the OperationContract declaration of the method you want to use this on addthe FaultContract attribute

[OperationContract]
[FaultContract(typeof(SPSoapFault))]

Now in the service you can throw FaultExceptions of this type

throw new FaultException<SPSoapFault>(new SPSoapFault("The byte array is null"), new FaultReason("Required parameter"));

Note that you must add a Fault Reason.

When calling this from a client application make sure you declare the faultexception that is in the web service references.

SPService.SPSoapFault spfault = new SPService.SPSoapFault();

the catch block of your try catch should include this

catch (FaultException<SPSoapFault> faultEx)
{

  spfault = faultEx.Detail;
 
string error = spfault.ErrorMsg;
  string reason = faultEx.Reason.ToString();
}

Tuesday, November 4, 2014

Dynamics CRM 2013 Microsoft Web Page Dialog error

If you use Dynamics CRM 2013 for any length of time then you will have noticed the Microsoft dialog box that pops up intermittently.  It seems to occur randomly and is hard to reproduce.  As far as I can see it doesn't result in any data loss so I just ignore it.

But the screen is irritating and doesn't give a good impression to first time users.

It can be disabled by logging on to CRM as the System Administrator and going to Administration and Privacy Preferences. On the Privacy Preferences dialog click the Error Reporting tab. Select "Specify the Web application error notification preferences on behalf of users" checkbox and then select the radio button "Never send an error report to Microsoft".

The errors are still happening but at least the screen isn't popping up. 

Saturday, July 26, 2014

Unit Testing Dynamics CRM Plugins

Now there are lots of approaches to unit testing Dynamics CRM plugins and some frameworks for creating Mocks

Recently an XRM Test Framework has been made available

But I like the simple approach(es) outlined in this blog.  It doesn't use any tools because you write the code yourself which can be an advantage or a drawback.  If you don't have time to evaluate a tool and think you can build unit tests quickly, then this is probably a good approach. 

The first approach described in this blog may involve refactoring your code but it is the best approach if you want to run unit tests during an automated build process.  It involves moving most of the code out of the Execute method of the Plug-in and putting it into a "logic" Class Library.  So the unit tests simply call the Class library and you avoid having to go through the executing the plug-in.  OK, it may not test that the attribute filter you included is working properly but at least it tests your code prior to deployment and so would catch any errors.  These approaches, are not mutually exclusive, you would combine them to ensure the quality of the code. 

 

Wednesday, July 23, 2014

VS 2012 and TFS 2013 Build Process Templates - How to add DefaultTemplate.11.1.xaml

Today was one of those days that forced me to blog. It was a deeply frustrating day but ended on a high and I thought to myself why hasn't anyone blogged that before?

I have a VS 2012 solution that was held in TFS 2012 and I've now moved it to TFS 2013.  I did not want to upgrade the development team to VS 2013 just at this moment. Besides, I thought VS 2012 and TFS 2013 were compatible, right?  I was trying to set up automated builds so I created a Build Controller on my build server using the TFS 2013 DVD image.

I opened my solution and selected create Build Definition and selected the Default Template (TfvcTemplate.12.xaml). I immediately saw lots of errors and a few minutes Googling revealed that you can't use this TFS 2013 template for VS 2012 projects.

Now the link just below the drop down list of build process templates should direct you to where the templates are stored in Source Code Explorer. Now my link showed #/1/BuildProcessTemplates/TfvcTemplate.12.xaml and that navigated to nowhere. I mean the link doesn't even start with $ so how was that ever going to work?

So I started trying to find the XAML files for the Build Process Template that the Build Controller was using. If they weren't in TFS then presumably they were on the hard drive. No. Then how do I add a Build Process template to the list? Hours of searching revealed nothing and this was the deeply frustrating part of the day.

Then I found this blog. The author very kindly provides the source code to create a Console application that will allow you to list the Build Process Templates you have and crucially to add a new one.  BTW, the two references that you need to add for this to work can be found in the GAC (C:\Windows\assembly\GAC_MSIL)

Now I already had the DefaultTemplate.11.1.xaml file that I needed for my VS 2012 solution because it was sitting there in the BuildProcessTemplates directory beneath the root of my project in TFS. 

I used the command line similar to this:

ManageBuildTemplates.exe http://jpricket-test:8080/tfs/TestCollection0 TestProject add  $/TestProject/BuildProcessTemplates/MyTemplate.xaml

to add my Build Process Template.  As soon as I selected a new Build Definition I could see my newly added template and I was cooking.  A few minutes later I had my first successful automated build.  From the depths of despair to deep joy in just a few minutes. 

Which of course made me think - why hasn't anybody blogged this before? And Microsoft what the hell were you thinking? Why isn't this essential tool included with TFS?  Thanks again Jason Prickett for providing the source.

Friday, July 11, 2014

Automated Builds and Incrementing Version Numbers

Incrementing the version number when you do a build in Visual Studio seems an obvious requirement.

I found this great post on using a T4 template.  I followed the instructions carefully by creating a common DLL library project, removing the Class1.cs and adding a AssemblyVersion.tt file using the code that was provided. 

As the author points out you just need to save the T4 template file and it will create a .cs file with the assembly information in it with the appropriate build number.  In my case it created a AssemblyVersion.cs file.

As advised, I removed the  AssemblyVersion and AssemblyFileVersion attributes from AssemblyInfo.cs files of all the projects  that I wanted to apply this version number to. 

I then added the AssemblyVersion.cs file to the projects as a link but I moved the file under the Properties folder so it appears directly under AssemblyInfo.cs. If you've not added a link before, select Add existing.. and select the file and you will see the Add button in the dialog has a little down arrow which will reveal the "Add as a link" option. 

Sure enough when I built the solution, my DLLs had the correct version  number. 

But I realised I had to manually save the T4 file each time to refresh the version.cs file.  Now I want to have automated builds so I was looking for a way to process the T4 template before each build.

I finally found the answer from this blog entry. There is a TextTransform.exe file that will take the T4 template and produce the cs file. 

TextTransform.exe is located here
\Program Files\Common Files\Microsoft Shared\TextTemplating\11.0

or

\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\11.0

In the Pre-Build event of the version project I added this
"C:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\11.0\TextTransform.exe" ($ProjectDir)AssemblyVersion.tt -out ($ProjectDir)AssemblyVersion.cs

When I build the solution the version number is incremented.  Brilliant.

You can of course use lots of different variations for incrementing the build  or revision number. But remember the 4 parts are

major.minor.build.revision

I changed the original template to modify the AssemblyFileVersion only and not the AssemblyVersion.  I am still able to distinguish between the DLLs from different builds but the all important AssemblyVersion I control.  The first deployment will be version 1.0.0.0, I can then branch the code and change the T4 template to the next release 1.1.0.0.

To increment from the previous revision number using a T4 template there is a good blog post here. If you want to change both build and revision number use methods which use the declaration starting with <#+
using System.Reflection;
[assembly: AssemblyCompany("C Hoare & Co")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.<#= BuildNumber() #>.<#= RevisionNumber() #>")]
<#+
private int BuildNumber()
{
    int buildNumber = (int)(DateTime.UtcNow - new DateTime(2014,7,1)).TotalDays;
 return buildNumber;
 }
#>
<#+
private int RevisionNumber()
{
    int revisionNumber = 0 ; 
   // other code to increment revision number
    return revisionNumber;
}
#>

A couple of further points. 
1. Make sure there is no white space after the final #> or you will get an error.
2. If using TFS then add to the pre-build event, get latest version of AssemblyVersion,cs, check out before the TextTransform. In the Post Build event check the cs file back in.
3. To pause incrementing the build number, just unload the project from the solution.
4. SharePoint 2010 only recognises the major and minor number of the AssemblyVersion.  That's why controlling the AssemblyVersion is important, but you can increment the AssemblyFileVersion instead.

UPDATE
When I started using this method for automatic builds, I realised that using Pre and Post Build events to process the T4 template produced some errors.  I moved the commands into a PowerShell script and I execute this as a scheduled task an hour before my scheduled builds run.  I still have the version project but it becomes simple  container for the T4 template and the CS file, I don't need to add it to any solutions. I still like this approach. I have one place where I control Assembly and Assembly File Versions.