Wednesday, January 21, 2015

Runtime Exception building a solution from Visual Studio

Today I encountered the situation in which one of my assemblies gave the following exception

MissingFieldException was unhandled
An unhandled exception of type 'System.MissingFieldException' occurred in ...
Additional information: Field not found:

Visual studio gave the following hint: if a field in a class library has been removed, recompile any assemblies that reference that library.

After adding a new method to the failing assembly and calling it as expected I got the following exception: An unhandled exception of type 'System.MissingMethodException' occurred in

Somehow Visual Studio did not update the assembly, it may be that Visual Studio did not detect that the assembly changed or the assembly got locked and visual studio couldn’t update the assembly.

The solution was: Removing the assembly from the GAC C:\Windows\Microsoft.NET\assembly\GAC_MSIL

Monday, July 14, 2014

MVC 5 SharePoint 2013 and Data Annotations

 

Within MVC they have this great way of validation, they specify the restrains the data has to abide to on the model class. Unfortunately most data annotations that are available out of the box do not support SharePoint as backend data system. So You will soon find yourself in need to develop your own data annotations. To make live a little easier on you here is an example on how to make one. The example data annotation will test the list field combination to make sure that the value entered is unique.

using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace System.ComponentModel.DataAnnotations
{
public sealed class UniqueValueAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' moet uniek zijn";
private string _listName;
private string _fieldName;
private string _errorMessage;

public UniqueValueAttribute(string ListName, string FieldName) : base(_defaultErrorMessage)
{
_listName = ListName;
_fieldName = FieldName;
_errorMessage = _defaultErrorMessage;
}

public UniqueValueAttribute(string ListName, string FieldName, string ErrorMessage):base(ErrorMessage)
{
_listName = ListName;
_fieldName = FieldName;
_errorMessage = ErrorMessage;
}

public override string FormatErrorMessage(string name)
{
return string.Format(_errorMessage, name);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
return null;

string result = null;
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
if (spContext == null)
return new ValidationResult("SharePoint context was not found. Did you leave this screen open for a long time?");

using (ClientContext context = spContext.CreateAppOnlyClientContextForSPHost())
{
if (context != null)
{
var lst = context.Web.Lists.GetByTitle(_listName);
if (lst == null)
{
result =
String.Format("List name {0} could not be found in the SharePoint Web", _listName);
throw new ValidationException(result);
}
else
{
CamlQuery query = new CamlQuery();
string whereXml = @"<Where><Eq><FieldRef Name='{0}'></FieldRef><Value Type='Text'>{1}</Value></Eq></Where>";
whereXml =
String.Format(whereXml, _fieldName, value.ToString());
string viewXml = "<View><Query>{0}</Query></View>";
query.ViewXml =
String.Format(viewXml, whereXml);
ListItemCollection queryResult = lst.GetItems(query);
context.Load(queryResult);
context.ExecuteQuery();
if (queryResult != null && queryResult.Count > 0)
{
result =
String.Format(_errorMessage, _fieldName);
return new ValidationResult(result);
}
return null;
}
}
else
{
return new ValidationResult("No sharePoint context");
}
}
}
}
}

The use of the DataAnnotation is the same as it allways was in MVC just place the attribute on top of the property that needs the validation.


[UniqueValueAttribute("Foxy Documents", "Title", "De kamervraag met deze naam bestaat al")]
[Display(Name= "Naam")]
[Required(ErrorMessage="De naam van de Kamervraag is verplicht")]
public string Titel
{
get;
set;
}

To make sure that datetime fields where not defined in the past I also created a data annotation to validate datetime fields. I Noticed that there weren't many working answers on the forums so here you go

 

    public class DateTimeLargerThenNowMinus : ValidationAttribute
{
private const string _defaultErrorMessage = "Date is not allowed";
private string _errorMessage;
private DateTime _validationDate;

public DateTimeLargerThenNowMinus(int days=0, int months=0, int years=0, string ErrorMessage=_defaultErrorMessage)
:
base(ErrorMessage)
{
_validationDate =
DateTime.Now.AddDays(days * -1);
_validationDate = _validationDate.AddMonths(months * -1);
_validationDate = _validationDate.AddYears(years * -1);
_errorMessage = ErrorMessage;
}

public override string FormatErrorMessage(string name)
{
return string.Format(_errorMessage, name);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
return null;

var date = (DateTime)value;
if (date > _validationDate)
return null;
else
{
return new ValidationResult(_errorMessage);
}
}
}

Thursday, July 10, 2014

SharePoint 2013 X-FrameOptions in MVC 5

 

Modern browsers do not allow pages to be displayed within I-Frames by default. The idea of this security measure is to prevent ‘click-jacking’. Click Jacking is best explained by an example: Lets say you are working for a bank and create an internet page. Now a hacker can try to display your banking page in an I-Frame on his own site and adds a little extra functionality a key logger and a click jacker. With doing this the hacker will try to capture all the users actions and will potentially be able to get the users password.

This is why modern browsers prevent pages to be displayed in I-Frames by default.

However, within the secured confines of a SharePoint communicating with a on premise provider hosted app this security measure can be a hindrance.  Because SharePoint won’t be allowed to show the provider hosted pages in I-Frames. The good news, the developer of the pages can turn the security measure off for his application by stating that displaying the pages in I-Frames is allowed. This can be done with the ‘SuppressXFrameOptionsHeader’  in the Global.asax.

    public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);

AntiForgeryConfig.SuppressXFrameOptionsHeader = true;
}
}
This option was a default setting in MVC 4 however in the MVC 5 template for SharePoint this option needs to be added manually.

Thursday, April 10, 2014

Registering Provider hosted apps as trusted

 

Working with provider hosted apps you’re going to work with trusts. The combination of IssuerId and a Certificate will be used as identifier and apps that are signed with the combination of those two can be submitted to SharePoint as trusted.

The software supplier will deliver a certificate and an IssuerId. These can be registered as trusted using the following script: (replace the blue stuff and mind the IISReset)

# load in SharePoint snap-in
$snapin = Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue -PassThru
if ($snapin -eq $null) {
Write-Error "Unable to load the Microsoft.SharePoint.PowerShell Snapin! Have you installed SharePoint?"
return
}

$publicCertPath = "C:\Certificates\TestCert.cer"
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($publicCertPath)
New-SPTrustedRootAuthority -Name "TestCert" -Certificate $certificate
$realm = Get-SPAuthenticationRealm
$specificIssuerId = "11111111-1111-1111-1111-111111111111"
$fullIssuerIdentifier = $specificIssuerId + '@' + $realm
New-SPTrustedSecurityTokenIssuer -Name "TestCert" -Certificate $certificate -RegisteredIssuerName $fullIssuerIdentifier -IsTrustBroker
$fullIssuerIdentifier
iisreset


Removing the trust can be done by first retrieving the SecurityToken using


Get-SPTrustedSecurityToken


Getting the Id from the result and running


Remove-SPTrustedSecurityTokenIssuer –Identity …..The Id found in the previous step ……..

Friday, March 28, 2014

Problems with the SharePoint Provider hosted Apps

There are many manuals out there that will help with the basic installation of a provider hosted SharePoint environment. However, I still encountered exceptions on my machine and on machines of my fellow developers. For me this is the reason to write them down.

First up the Token Helper call: “string actorTokenString = new JsonWebSecurityTokenHandler().WriteTokenAsString(actorToken);” breaks with a System.Security.Cryptography.CryptographicException “Invalid provider type specified.”

This very useful exception is trying to tell you that the Cryptography can’t handle the Certificate “the key, pfx file” you are using. When you go to your web.config you’ve probably got something like this:

    <add key="ClientSigningCertificatePath" value="C:\Certificates\Wingtip.pfx"/>
<
add key="ClientSigningCertificatePassword" value="Password1"/>
<
add key="IssuerId" value="11111111-1111-1111-1111-111111111111"/>


The WingtipServer.pfx is of a wrong type or the .net framework is of a version that is not capable of understanding the type of certificate you are using. So this problem can be solved by : 


Replacing the pfx file with a new pfx file. Which is easy to do on a developer machine. Just go to IIS Click on your server, double click on the “Server Certificates” icon Click “Create Self Signed Certificate” This certificate will work.



The follow-up on the previous problem is: Getting a 401 access denied when connecting to the AppWeb this happens on the ExecuteQuery of a CSOM call. For example you are doing something like this:

            string SPAPPWebUrl = Request.QueryString["SPAppWebUrl"];
Uri appWebUrl = new Uri(SPAPPWebUrl);

//We are going to the appweb using nothing but the app only permissions
using (var contextAppWeb = TokenHelper.GetS2SClientContextWithWindowsIdentity(appWebUrl, null))
{
var web = contextAppWeb.Web;
contextAppWeb.Load(web);
contextAppWeb.ExecuteQuery();


When the ExecuteQuery method breaks with a 401 you probably forgot to register the certificate with the SharePoint farm. The following script was used in my case to register my newly created certificate with the SharePoint farm.

# load in SharePoint snap-in
$snapin = Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue -PassThru
if ($snapin -eq $null) {
Write-Error "Unable to load the Microsoft.SharePoint.PowerShell Snapin! Have you installed SharePoint?"
return
}

$publicCertPath = "C:\Certificates\Wingtip.cer"
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($publicCertPath)
New-SPTrustedRootAuthority -Name "WingtipCert" -Certificate $certificate
$realm = Get-SPAuthenticationRealm
$specificIssuerId = "11111111-1111-1111-1111-111111111111"
$fullIssuerIdentifier = $specificIssuerId + '@' + $realm
New-SPTrustedSecurityTokenIssuer -Name "WingtipCert" -Certificate $certificate -RegisteredIssuerName $fullIssuerIdentifier -IsTrustBroker
iisreset






Handeling AppEvents are failing on a developer machine. Using IIS Express Visual Studio will register a certificate of it’s own with the IIS Server on which SharePoint is running. But it won’t register that certificate with the SharePoint farm. That’s what needs to be done. It’s the same script as registering for the 401 just using a different certificate. You’ll need to go to IIS click on the server name –> Server Certificates and click Export



image


 



Server Error in ‘/’ Application. The specified network password is not correct. System.Security.Cryptography.CryptographicException. The ClientSigningCertificatePassword defined in the web.config is not correct.


System.Security.Cryptography.CryptographicException Access Denied.The account used for your application pool doesn’t have enough rights.The account needs to be able to access the local machine certificate store.


Server Error in ‘/’ Application The system cannot find the file specified. System.Security.Cryptography.CryptographicException. This exception may be caused by a wrong ClientSigningCerticicatePath in the web.config file.

TokenHelper.CreateAppEventClientContext returns a TypeInitializationException, Inner Exception shows a System.Security.Cryptography.CryptographicException: "The system cannot find the file specified" possible cause is that the certificate defined in the web.config is not pointing to the right folder or there is a typo in the config.

Good luck SharePointing!

Thursday, January 9, 2014

SharePoint 2013 CSV Bulk Taxonomy TermSet Importer/Exporter

 

I noticed that the tool that worked perfectly for SharePoint 2010 for exporting and importing term sets was not available for SharePoint 2013.|
All credits still go to the original developer, all I did was change some references and recompile the project.

It can be downloaded here : SharePoint 2013 CSV Bulk Taxonomy TermSet Importer/Exporter

Wednesday, November 6, 2013

SharePoint October 2013 patch 503 error

 

Just installed the Oktober patch for SharePoint server 2013. http://support.microsoft.com/kb/2825647 
I knew that after installing a patch you should always run the SharePoint Products 2013 Configuration Wizard so I did. However the patch still left me with a “HTTP Error 503. The service is unavailable.” error.

Solving this is rather easy, SharePoint patches have the tendency of shutting down the IIS application pools. So all you have to do is start up IIS manager navigate to the pools and hit the ‘play’ button.

 

Here you can see that the installation of the patch stops all pools but doesn’t start them back up again after finishing the installation.

image