Tag Archives: programming

CAML Query did not return result for Date Range query

Having developing SharePoint for so many years, I just got to know that you CANNOT perform CAML Query for Date Range where your ISO Value is a DateTime.MinValue.

CAML Query does not support Date Value of DateTime.MinValue

SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.MinValue)

For example, if you were to query the Event Date Time from day 1

<Geq> 
 <FieldRef Name='EventDate' />
 <Value IncludeTimeValue='FALSE' Type = 'DateTime'>" + 
SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.MinValue) + @" </Value>
 </Geq>

DO NOT DO this. You will never get any result. The minimal value that you can insert (had some googling around the web), is 1900/01/01.

Just make sure you conduct a date time in 1900 year onwards and you will be safe.

SharePoint Custom Solution Branding and Tips – Part 2

This is part 2 on how to brand your SharePoint Solution. If you haven’t read my part 1, please do so here.

Often than not, you would want to include your custom List Definition/Instance to be provisioned into your Solution file. In SharePoint 2013, they’ve changed the Site Content page drastically and you can’t really Ignore the BIG BIG icon for each List/Library within your site.

sharepoint site content list icon image

It’s fancy and it’s sleek. So how can I create one for my own solution?

As usual, there isn’t gonna be much documentation provided in MSDN. And most of the time, you just got to crack your head and dig your way out. I’m writing this post here so that you can at least Find my article when you’re googling around.

How to set Image for your List Definition / List Instance

Assuming you have already created a SharePoint 2013 Project solution and added a List Definition.

Add SharePoint “Images” mapped folder into your Project as shown below

right click add image layout folder sharepoint

Prepare TWO icons and you must ensure that the following rules are followed:

  1. Both icons must have same file extension.
  2. One icon is in 16×16 pixel size and the other one is in 96×96 pixel size
  3. File Name of the 16×16 icon must starts with small I: “it” e.g. itmyfancyicon.png
  4. File Name of the 96×96 icon must starts with small L: “lt” e.g. ltmyfancyicon.png
  5. Both file names must be exactly the same except for the first character.

To better helping you to understand, I’m including the two images used below

itmyfancyicon.png itmyfancyicon  (16×16)                  ltmyfancyicon.png ltmyfancyicon (96×96)

After meeting these rules, you need to include them into the Images mapped folder and be placed into the same Folder. (Must)

sharepoint list icon image same folder

Lastly, go to the Elements.xml file of the list definition and modify the Image Attribute to point to “it” (16×16 pixel size) image as shown below. DO NOT specify the one that starts with “L”.

http://wp.ahcheng.com/wp-content/uploads/2016/01/sharepoint-list-definition-image-url-attribute.png

Once you specified to the small “i” image, deploy it and you should see your List is having a nice and Correct images!

http://wp.ahcheng.com/wp-content/uploads/2016/01/sharepoint-list-definition-image-how-to-set-it-properly.png

 

 

EditorPart does not have an ID

Yet another error that I’ve encountered when customizing ToolPart (aka EditorPart) for my own SharePoint Web Part.

The task is to create a custom tool part with custom control that displays a list of SharePoint Lists. This custom control contains a post back logic to update another drop down list base on the selected value.

In order to display your toolpart into the Web Part properties pane, you would need to override the following virtual method in System.Web.UI.WebControls.WebParts.WebPart class


public override EditorPartCollection CreateEditorParts()

I bumped into this error “EditorPart does not have an ID” with the following code that was not done correctly


public override EditorPartCollection CreateEditorParts()
{
 ArrayList editorArray = new ArrayList();
 MyEditorPart part = new MyEditorPart() { ID = this.ID + "_editorPart1" };
 editorArray.Add(part);
 editorArray.Add(new WebPartToolPart() );
 editorArray.Add(new CustomPropertyToolPart());
 EditorPartCollection editorParts = new EditorPartCollection(editorArray);
 return editorParts;

}

The use of including WebPartToolPart and CustompropertyToolPart is to ensure that your custom web part would still display the OOTB Web Part Properties pane (which has the functionality to change Height, Width, ChromeType etc etc)

To use them correctly, you would need to specify an ID for each of the class. After applying the code below, the error is gone.


public override EditorPartCollection CreateEditorParts()
{
 ArrayList editorArray = new ArrayList();
 MyEditorPart part = new MyEditorPart() { ID = this.ID + "_editorPart" };
 editorArray.Add(part);
 WebPartToolPart wpToolPart = new WebPartToolPart() { ID = this.ID + "_wpToolPart" };
editorArray.Add(wpToolPart);

 CustomPropertyToolPart cpToolPart = new CustomPropertyToolPart() { ID = this.ID + "_cpToolPart" };
 editorArray.Add(cpToolPart);
 EditorPartCollection editorParts = new EditorPartCollection(editorArray);
 return editorParts;
}

A Web Part or Web Form Control on this Page cannot be displayed or imported. The type could not be found or it is not registered as safe.

This is a very common error that SharePoint Developers often face. As stated in the error message, this is due to SafeControl Elements in Web.Config file of your SharePoint Application not being added correctly, or perhaps pointing to the wrong type name.

Resolution

To solve this issue, you’ll need to make sure that the SafeControl Entries in your SharePoint solution projects is configured correctly.

Step 1 – Find out what is the correct type name.

  1. Navigate to your .webpart file in Visual Studio that you’ve misconfigured.
  2. Double clicking it to open the webpart file.
  3. Copy the Type Name and exclude the last node
    web part register 1
  4. Alternatively, go to your web part .cs file and copy the Namespace
    web part register 2

Now that you have the correct type name. You need to…

Step 2 – Specify the right Safe Entry

  1. Click on the Web Part
  2. Under Properties panel, click on the … icon beside Safe Control Entries
    web part register 3
  3. Enter the value found in Step 1 into Namespace field as shown below.
    web part register 4
  4. Deploy and Done!

Convert SharePoint 2010 Solution to 2013 – 15 Hive Folder only

Bumped into this problem where I was trying to convert old codes from SharePoint 2010 to SharePoint 2013.

One issue that you will encounter is that all your Element Files being uploaded to 14 Hive folder (the old 2010 path) rather than the new 15 Hive folder.

If you deploy your solution directly into a SP2013 environment, you will encounter reference link broken or file not found due to codes/files not being deployed to 15 Hive.

One Workaround is to actually deploy your solution with switch -CompatibilityLevel All (for detail please refer here ). However, you can’t always remember to do this steps and in order for you to really upgrade your solution to SP2013, You need to make some changes to the manifest file. And steps below show you how to change it permanently and only stick to 15 hive folder.

Resolution

  1. Open your SharePoint solution via Visual Studio.
  2. Expand the Package folder and Double click “Package.package
  3. Under Properties Panel, change the property “SharePoint Product Version” from 14.0 to 15.0
    upgrade sp2010 to sp2013 solution
  4. Package it and done!

P/S What I additional did to make sure there is no reference link broken is to Find ALL “_layouts/“, “_CONTROLTEMPLATES/” and replace with “_layouts/15/” and “_CONTROLTEMPLATES/15/

SharePoint Custom Solution Branding and Tips – Part 1

Today, I want to talk about some of the good practices when it comes to SharePoint custom code development. More often than not, you would learn that SharePoint custom solution requires you to create Feature (and usually it’s automatically created when you pick any of the default SharePoint Project template e.g. Visual Web Part) to deploy your web part, style sheet, JavaScript files, or master pages.

I can understand that the Microsoft VS team is trying to help SharePoint Developers setting up a working solution as easy and as best as they could. What we need to really take note or at least be aware of is those default values assigned to the template. Below are some of the items in which I personally think that it should not be left unchanged or not thought thoroughly in order to develop a quality solution.

Namespace

Before even creating a new SharePoint 2010/2013 project, please think through the namespace that you want to use. Changing of namespace after you have tons of web parts, feature or pages will kill you. And I kid you not, using VS rename feature does not 100% guarantee you that the code will not break. I have experienced it, and it really takes you a lot of time to just renaming a namespace. (if you are new to SharePoint Development of course)

What I always like to use for namespace naming convention is as per below format

[Company Name].[Type/Name of the solution].[Sub type]

e.g. Microsoft.Branding, Microsoft.Branding.UserControls, Microsoft.Branding.DelegateControls

I would say it is not advisable to have more than 3 levels as it would introduce a very lengthy code referencing.

And I would also suggest using sub type like “UserControls”, “WebParts” or “WebPages” to organize your codes accordingly. It makes the next developer who is taking over your code easier to understand.

Feature Name

Sorry to say that this is one of the item that I dislike most when you found out that your developers did not use it correctly or not even care about changing the name of the feature!

You may not see the impact for now but once you have your code deployed to your customer’s SharePoint environment, it would really look bad and unprofessional to have this appearing in their Site Collection Feature or Manage Site Feature page.

sharepoint feature name bad practice

If you care enough, you will notice that only your custom feature’s name is ending with the numeric “1”. As if there is feature 2 and so on? LOL hell no!

Well, as a new beginner, you will likely to use the SharePoint – Visual Web Part template for a quick start.

sharepoint visual web part

What this template provides by default in the solution is the feature, package and a visual web part. Refer pic below

shareopint default feature name

Please please, remove the “1” and use a proper name.

Note that if you have already deployed your solution to production. After changing the name, you have to retract existing solution by running “Uninstall-SPSolution”, “Remove-SPSolution” and subsequently “Add-SPSolution” and “Install-SPSolution”. You should not use “Update-SPSolution” or else you will hit error deploying it.

Please also use a meaningful description. =)

Feature Image

The next thing I want to talk about is the icon of SharePoint feature. SharePoint by default assign an icon GenericFeature for your feature. As the image name suggested, it is a Generic Feature gif and in order to out stand or brand your feature, I would always like to use a custom image for my feature.

One simple reason is that it makes life easier when there is a lot of features within your SharePoint Site and you need to scroll through the entire list in order to activate or deactivate your feature.

sharepoint long list of feature

How to not miss the “EASY” icon if the color is outstanding enough. You know what I’m trying to say. Outstanding!

The following paragraph describes how you can actually add feature icon into your SharePoint Feature.

First of all, create a good icon for your feature, and put it into your SharePoint Solution.

sharepoint add images mapped folderSimply right click the project, hover to Add and click “SharePoint Images Mapped Folder” (if you already mapped, this option will be grey out)

Once you have it mapped, you can just dump your  images into the mapped image folder and it will automatically be included into your package. The relative URL of your images folder is always starting from “/_layouts/15/IMAGES/”

How to know if it is really going into that URL? You can check by looking into the Property of the Images mapped folder – Deployment Location where it stated “{SharePointRoot}\Template\Images”. This actually goes to your SharePoint 15 hives (SP2013) of your deployed server and if you look into IIS Manager for your SharePoint Web application. This folder is actually mapped as a Virtual Directory with path

sharepoint virtual directory image

Once you have your image prepared in the solution, next step is to tell your Feature to use the image. Easy. Go to your feature element files as shown below.

Simply place your cursor right before the end of the “>” tag and you should see the intellisence starting to show up. At this stage, the attribute that you would need to pick is quite self-explanatory.

sharepoint feature auto suggestion

Insert the ImageUrl. Just remember to make sure the url is correctly populated. Sample as shown below.

sharepoint feature image url example

Once you have it specified correctly, deploy it and you should see that your feature is now with your custom icon. Sample below shows not really a good example, but please use a size that you find fits.

sharepoint feature image output

 

Custom Action Group and Action

Another item that worth mentioning when doing SharePoint development is the Custom Action and Group. Since SharePoint 2010 (not sure about SharePoint 2007). It introduces a new feature where you can inject Stuff (could be links, could be Ribbon action or event Site Action) into certain area of your SharePoint pages.

Basically, the idea is that there is list of area (which it is called Location) in SharePoint where you can add/remove Stuff and within each area, there is another sub-area (which is called Group ID) if you need to further scoping down into a more specific area.

You can refer to MSDN https://msdn.microsoft.com/en-us/library/office/bb802730.aspx for Location and GroupID that you can make use of.

Things can be made easier if you need to display some custom site action or site settings link for your user to access certain page (be it your custom application page or SharePoint OOTB pages where it may not be displayed by default e.g. /_layouts/groups.aspx (Groups Page)).

I’m going to share how to go about doing it.

First of all, go to MSDN link above and identify the Location that you want to use. For the simplicity, let use Microsoft.SharePoint.SiteSettings as a example.

So let assume you want to insert a hyperlink into Site Setting page.

Go to your VS Project, Right click and add new item. Select Empty Element as shown

sharepoint empty element

Pick a nice name and hit Add. Note that once it is added, you can find a file called “Elements.xml” being added. Open it and,

Insert the following code.

sharepoint feature site setting example

 

Things that you need to note here is the GroupId and Location used. I added a Custom Action Group with a custom id, but using a valid Location. Subsequently, create another CustomAction and use the custom GroupId and the same valid Location (You still need to specify the same value as the CustomActionGroup or else it won’t work).

The Sequence in the Custom Action Group tells how earlier you want your group to be rendered in the Location. In the example above, 1 is being the first to render.

sharepoint site setting link

 

Hence it will be at the top of all existing group.

Things get a little bit complicated here if, let say other feature have used the same Sequence number as you did. In this case, the later registered ones will be displayed first.

Like example below. Group A being registered later and hence it is displayed first before the Group B.

sharepoint feature sequence does matters

 

Note that you need not to order the Custom Action xml to below Custom Action Group. SharePoint can still recognize them.

 

I have much more to share but that’s it for today! I hope above info and tips can help giving you some ideas and to be able to build a good SharePoint solution!

 

Read part 2 here

SharePoint Limited Access Permission – Careful when using BreakInheritance

This post is for SharePoint Developer or Admin who deals with SharePoint APIs (PowerShell or C#)

I have recently discovered a killing command from SharePoint that could kill your SharePoint Day. At times, you will need to configure a Unique permission to document/file for Content Sharing purposes. Typical feature which your end user will ask is to Share a certain document or folder to only certain group of people. Although it is recommend to Share using SharePoint Group which more manageable when it comes to a big Content management system, sometime you prefer to make a easier way out by just assigning to the Individual Users. (Less group to manage and you CAN Afford to loss the permission when things go wrong… and yes, this post will tell you why and how it goes wrong)

With much user friendly SharePoint “Share With” feature, you could break inheritance, grant new user permission so on and so forth. You can’t stop user from doing it, cause it is so apparent nowadays in SharePoint 2013

break and grant permission

Or you can run PowerShell script to Get the ListItem (or to be precise, SPSecurableObject Base Type object), subsequently execute  $object.BreakInheritance($false) and start adding SPRoleAssignment object.

If you have noticed this API

void ISecurableObject.BreakRoleInheritance(bool copyRoleAssignments)

 

This command allows you to quickly remove all existing RoleAssignment (from inheriting parent object permission) and so you can start adding Custom permission that you desired.

Important! This is Extremely Dangerous. Why? Because if you carefully loop into the $object.RoleAssignments (SPRoleAssignmentCollection) property, you will discover that some role definition bindings are named “Limited Access”. In SharePoint 2010, you can easily notice this definition through the permission setting page whereas in SharePoint 2013, it is hidden by default (which is more scarier cause you didn’t even know its existence).

Why is this Limited Access permission? There are many articles out there telling you why and why. I’m not gonna cover that here.

But if you really intend to so-called Cleanse the messy permission list that you have already added, the advice is Don’t.

Let me give you an example of how this BreakInheritance way of breaking parent permission can cause you problem.

By executing BreakInheritance(False), you are technically removing ALL Role Assignments from this object, which include the Limited Access permission granted automatically by SharePoint. You will usually see a lot of limited access for Document library and Web, cause the children within it are likely to be requested (by user) to have unique custom permission.

reset and break with false

 

For Example

  • Web 1 
    • Document Library A
      • Folder a (Break inheritance)
        • File
      • Folder b 

Assuming you have a “Folder a” with broken inheritance permission for UniqueUserA. Upon granting this unique permission, SharePoint automatically creates a Role Assignment for UniqueUserA with “Limited Access” permission to Web1 because Document Library A is inheriting permission from Web1 and hence it is added into Web1 instead.

Somehow or other, you need to change/script to change the permission for Web 1 object up there (the one with Limited Access), by purging the limited access granted to UniqueUserA. the permission that you granted previously to “Folder a” will be DELETED automatically! Yes, Automatically, seamlessly, without-your-knowingly.

And what is going to happen after that? Your lovely user UniqueUserA will send email you, telling you that he has no permission to access files or folder a. Not to mention if you have many Unique permission granted for sub folders within that document library.

Now, the Task you need to ask yourself is – How to still be able to remove existing permission while preserving the Unique configured child permission.

I came out with a simple PowerShell script that allows me to clear the permission. I think it can be easily translated into C# for code behind implementation.


#############################################################################
# Clearing Permission while keeping Limited Access user - Important #
#############################################################################
function ClearPermission
{
 Param([Microsoft.SharePoint.SPSecurableObject]$obj)

 $roleAssignments = $obj.RoleAssignments;
 $count = $roleAssignments.Count;
 for($i = 0; $i -lt $count ; $i++)
 {
  $roleAssignment = $roleAssignments[$i];
  $bindingCount = $roleAssignment.RoleDefinitionBindings.Count
  $clearCounter = 0;
  for($j = 0; $j -lt $bindingCount ; $j++)
  {
   $roleBinding = $roleAssignment.RoleDefinitionBindings[$clearCounter];
   if($roleBinding.Name -ne "Limited Access")
   {
    $roleAssignment.RoleDefinitionBindings.Remove($clearCounter);
   }
   else
   {
    $clearCounter++;
   }
  }
 }
 $obj.Update();
}

What it simply does is to loop through the Role Assignment Collection and delete only Binding with definition of Limited Access. Note that I do not loop via ForEach loop as when you looping the collection, you cannot delete the object within the collection. You can try and you will end up seeing error.

How to use:


Add-PSSnapin Microsoft.SharePoint.PowerShell

$w = Get-SPWeb https://yoursite

ClearPermission $w;

#add your unique permission here.

#additional code to add role assignement (permission)

$user = $w.EnsureUser("domainX\LoginNameY");

$roleAssignment = New-Object Microsoft.SharePoint.SPRoleAssignment($user);

$roleDefinition = $w.RoleDefinitions["Full Control"]

$roleAssignment.RoleDefinitionBindings.Add($roleDefinition)

$w.Update();

Hope it helps

Facebook Access Token Request does not work in IE 8

Integrating Facebook Feeds to your Web Application could be a very common thing nowadays. Supporting this integration across different browser could be a headache for most developers out there. Including me myself.

At the end of this session, you will know how to perform an AJAX request to query Facebook feeds access token at client side which support IE 8 Browsers and all other Modern browsers. Using jQuery 1.9

Note: You can only do client side query if your web servers are not having internet connectivity to Facebook. Especially “graph.facebook.com” where you perform access token retrieval and Graph API.

First of all, you need a jQuery and Facebook JS like this

<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head></pre>
<body>
 <div id="fb-root">
 <script type="text/javascript" src="https://connect.facebook.net/en_US/all.js"></script>
 </div>
...
</body>

And then you need this to initialise FB SDK

<script type="text/javascript">
var access_tokenParam = ""; //to store the access token
var appId = "" // YOUR APP ID HERE
var appSecret = "" //APP SECRET;

window.fbAsyncInit = function () {
 FB.init({
 appId: appId, //App Id
 status: true,
 xfbml: true
 });

};
</script>

Lastly, you need create a Facebook App (if you have not) for an App ID and App Secret key. You can get it here App DashBoard

Note that you need to set your App to use the testing domain URL. In my cases, i use “facebooktest.com”

facebook app dashboard setting

Not to forget to map this URL to your 127.0.0.1 in hosts file (C:\Windows\System32\drivers\etc\hosts)

127.0.0.1 facebooktest.com

To share what happened before i come to a workaround, below are the JavaScript to obtain Facebook access token to perform Graph API. THIS WORKS in all other browser EXCEPT Internet Explore 8.


$.support.cors = true; //

$.ajax({
 type: "POST",
 url: "https://graph.facebook.com/oauth/access_token",
 cache: false,
 data: {
 "client_id": appId,
 "client_secret": appSecret,
 "grant_type": "client_credentials"
 },
 error: function (xhr, status, error) {

//ERROR THROWN TypeError: Access is Denied for IE8
 },
 success: function (response) {

 },
 complete: function (request, textStatus) {
 if (request.responseText != null) {
 access_tokenParam = request.responseText.split('=')[0] + "=" + escape(request.responseText.split('=')[1]);
//access_tokenParam will be the token that you will then be used for subsequently Graph call
 }

}
 });

If this script runs on IE 8, you will hit TypeError: Access is Denied This is due to IE 8 does not use the XMLHttpRequest, but an alternative object named XDomainRequest. Some googling suggested using JSONP. Alright, lets try.

$.ajax({
 type: "POST",
 url: "https://graph.facebook.com/oauth/access_token",
 cache: false,
 dataType: "jsonp",
 data: {
 "client_id": appId,
 "client_secret": appSecret,
 "grant_type": "client_credentials"
 },

error: function (xhr, status, error) {

//ERROR Thrown "Parseerror" in IE8 AGAIN...
 });

The above both attempts to get the access token failed in IE8. After digging deeper to Facebook Documentation, i found this

There is another method to make calls to the Graph API that doesn't require using a generated app token. You can just pass your app id and app secret as the access_token parameter when you make a call:
http://graph.facebook.com/endpoint?key=value&access_token=app_id|app_secret
The choice to use a generated access token vs. this method depends on where you hide your app secret.

Holy cow…

What you need to do is just setting your access token as per below

access_tokenParam = “access_token=XXX|YYY”

where XXX is your App ID and YYY is your App Secret. e.g. “access_token=778487422177917|gu_TZwkQe5jtBj7VvZpMJX8odlx”

don’t try to use it, it is not valid =)

Knowning that the Access Token needs not to be provided by Graph, you may then perform API call like this (taking my posts as example)


access_tokenParam = 'access_token=' + appId + '|' + appSecret;
renderFBNewsFeed('yihaa5', access_tokenParam);

function renderFBNewsFeed(id, access_tokenParam) {
 var url = '/' + id + '/posts?' + access_tokenParam;
 FB.api(url, { return_ssl_resources: 1 }, function (response) {
 if (response.data) {
 var html = "";
 for (var i = 0; i < response.data.length; i++) {
 var obj = response.data[i];
 var fakeTitle = obj.name ? obj.name : (obj.story ? obj.story : obj.message );
 var fakeDes = obj.description? obj.description : obj.caption;
 html += "<h2>" + fakeTitle + "</h2>";
 html += "<h3>" + fakeDes + "</h3>";
 }
 $("#fbNewsWrapper").html(html);
 }
 });

}

You can find the entire html file here Hope it helps!

Change the default settings for newly created SharePoint Document Library

Thought it would be helpful to share this.

As you know, SharePoint Document Library by default, if you just simply create one, are not turned on with Version Control. This could rather prone to human mistake or mis-configuration whenever you need to provision a new document library.

This is how I fulfill this.

Imagine i need to have the version control turn on, and with the following settings

version history limits

What you need to do is to create a custom event receiver with List Added handler

Fire up your Visual Studio, create a SharePoint Farm solution and add your new event receiver

New Event Receiver

Select List Events and tick “A list was added”

Event Receiver Setting

In the ListAdded method, kindly do a checking before the code is firing, the below TemplateId 101 means Document Library


if (properties.List != null && properties.TemplateId == 101 && properties.Web != null)
 {

try
 {
 SPList docList = properties.List;//.Lists[properties.ListId];
 docList.EnableVersioning = true;
 docList.EnableMinorVersions = true;
 docList.MajorVersionLimit = 3;
 docList.MajorWithMinorVersionsLimit = 20;

//this.EventFiringEnabled = false;
 docList.Update();
 }
catch (Exception ex)
 {

//Do something...

}

}

If you do this, you will hit this error when creating a new document library

The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.

This is due to the Synchronisation mode for ListAdded event by default is “Asynchronous”.
You MUST DO the following

Open the Element.xml created via Visual Studio.
Add a “<Synchronization>Synchronous</Synchronization>” node into your receiver xml

<Receiver>
 <Name>SharePointSettingEventReceiverListAdded</Name>
 <Type>ListAdded</Type>
 <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
 <Class>MOT.EventReceiver.SharePointSettingEventReceiver.SharePointSettingEventReceiver</Class>
 <SequenceNumber>10000</SequenceNumber>
 <Synchronization>Synchronous</Synchronization>
 </Receiver>
 </Receivers>

Deploy your solution and hooray~