Friday 7 October 2011

Postbuild events for Sharepoint projects in Visual Studio 2010

This is really helpful:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe" -u $(TargetName)
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe" -i "$(TargetPath)"
%windir%\system32\inetsrv\AppCmd recycle APPPOOL "SharePoint - 80"

It automatically adds dll to GAC and recycles application pool.

Friday 27 May 2011

Creating folder in a document library and creating file inside that folder

In order to create programmatically folder inside library and then create file inside that folder you can use following code:

using (SPWeb web = properties.Web.Site.OpenWeb("/web"))
{
 list = web.Lists["My list"];

 SPFolderCollection collection = list.RootFolder.SubFolders;
 //Create new folder
 SPFolder folder = collection.Add("Automatically created at " + DateTime.Now.ToString().Replace(":", "-"));
 item = folder.Item;
 item[SPBuiltInFieldId.Comments] = "Automatically created";

 this.EventFiringEnabled = false;
 try
 {
  item.Update();
 }
 finally
 {
  this.EventFiringEnabled = true;
 }
}
//insert attachment to folder
if (item.Folder != null)
{
 SPFolder folder = item.Folder;
 if (properties.ListItem.Attachments.Count > 0)
 {
  SPFile file = item.Web.Site.RootWeb.GetFile(properties.ListItem.Attachments.UrlPrefix + properties.ListItem.Attachments[0]);
  byte[] imageData = file.OpenBinary();
  SPListItem contractItem = folder.Files.Add(properties.ListItem.Attachments[0], imageData).Item;
  contractItem.Update();
 }
}

Thursday 26 May 2011

Creating a generic list of an anonymous type ?!?

Yesterday I was wondering how to create a generic list of an anonymous type, something like this:
var employee = new { FirstName = "Jan", LastName = "Kowalski" };
var employeeList = new List();
At the beginning I though this was impossible, but the resolution is closer than it appears:

var employee = new { FirstName = "Jan", LastName = "Kowalski" };
var employeeList = (new[] {employee}).ToList();
employeeList.Clear();

We can extend it to create factory creating those lists:
public static List<T> CreateList<T>(T itemOftype)
{
   List<T> newList = new List<T>();
   return newList;
}

Tuesday 5 April 2011

WCF tutorial part 03 - setting endpoints inside app.config file

In this part I'm going to show you how to set endpoints inside app.config file instead of heaving them in code. This way we can easily change them in the future without need to recompile our application.

Host
From Program.cs file remove line with baseAddress definition, also change ServiceHost construction to following
ServiceHost serviceHost = new ServiceHost(typeof(MyService.Service));
our Program.cs file Main method will start with
ServiceHost serviceHost = new ServiceHost(typeof(MyService.Service));
try
{    
 serviceHost.Open();
 Console.WriteLine("The service is ready.");
 Console.WriteLine("Press <ENTER> to terminate service.");
 Console.ReadLine();

 serviceHost.Close();
}
...catches etc.
Add App.config file to WCFHost project
Put this into this file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
              <behavior name="Metadata">
                <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8000/meta" />
              </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="Metadata" name="MyService.Service">
                <endpoint address="net.tcp://localhost:9000/tcp" binding="netTcpBinding"
                    contract="MyService.IService" listenUriMode="Explicit" />
            </service>
        </services>
    </system.serviceModel>
</configuration>
First I'm adding Metadata behavior, it's almost equal to putting this in code:
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(smb);
I'm also specifying where will be metadata available (http://localhost:8000/meta)
Then I'm creating new tcp endpoint at address net.tcp://localhost:9000/tcp.

Client
Now we need to recofigure our client. Service reference cannot be updated since metadata location has changed. First, start your host project (remember setting startup project mode to current selection). If the host is up, right click on ServiceReference and choose Configure Service Reference...


If you receive error similiar to this one:
remove your service reference completely and add new service reference.
In both cases as new address enter http://localhost:8000/meta . Service should have been discovered (click Go):
 If it's discovered correct Namespace to ServiceReference and click OK.
Start you're client - it should connect to the host without any further changes needed.
You can download source code from here:
http://sites.google.com/site/terespl/files/WCFTutorialpart03.zip

Thursday 31 March 2011

Interesting online programming course (in polish only)

If you are interested in online programming course covering ASP.NET MVC 3 programming you must definitely visit this address http://codingtv.pl/ . The authors: Łukasz Gąsior and Andrzej Kowal are also speaking about tools which are used for creating project.
In polish only.

Wednesday 30 March 2011

Endpoints using 'UriTemplate' cannot be used with 'System.ServiceModel.Description.WebScriptEnablingBehavior'.

I was getting this exception (Endpoints using 'UriTemplate' cannot be used with 'System.ServiceModel.Description.WebScriptEnablingBehavior'.) all the time, after I specified my service contract (I was using WebScriptEnablingBehavior):
public interface ICourseService
{
 [WebGet(UriTemplate = "GetCourseList", ResponseFormat = WebMessageFormat.Json)]
 [OperationContract]
 List GetCourseList();
}
Well... it turns out, this parameter combination is forbidden, instead use this:
public interface ICourseService
{
 [WebGet(ResponseFormat = WebMessageFormat.Json)]
 [OperationContract]
 List GetCourseList();
}
notice, there's no UriTemplate. Eventhough you can still navigate to: http://localhost:60377/TestSite/test.svc/GetMyList and it will retrieve JSON file.

Sunday 27 March 2011

WCF tutorial part 02 - separating service from host

In this tutorial we're going to separate service from host. In my opinion it's a good pattern to have service separated from host.
Let's add a new project to solution and call it MyService
After this, drag IService.cs and Service.cs files from WCFHost to MyService project. Remove them from original WCFHost project.
Change namespace in those files to MyService.
Make interface and class publicly accessible by adding public modifier to their definitions.

Add reference in WCFHost project to MyService project:

Build WCFHost project, this should build MyService library and copy the dll file to WCFHost project.

We need to make few adjustments in our host, to compile it. Only this section contains changes:
- in line 2 we're updating service type to MyService.Service
- in line 6 we're updating type of interface used to MyService.IService

Uri baseAddress = new Uri("http://localhost:8000/Service");
ServiceHost serviceHost = new ServiceHost(typeof(MyService.Service), baseAddress);
try
{
 serviceHost.AddServiceEndpoint(
  typeof(MyService.IService),
  new WSHttpBinding(),
  "Service");

 ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
 smb.HttpGetEnabled = true;
 serviceHost.Description.Behaviors.Add(smb);

 serviceHost.Open();
 Console.WriteLine("The service is ready.");
 Console.WriteLine("Press <ENTER> to terminate service.");
 Console.ReadLine();

 serviceHost.Close();
} 
 
We should update service reference in our client project, in order to do this you should:
  1. set startup project mode to current selection, 
  2. start WCFHost,
  3. rightclick on Service References - ServiceReference in WCFClient project and choose "Update Reference"
  4. start WCFClient project - there should be no errors.
Congratulations - you're done.
You can download project from here: http://sites.google.com/site/terespl/files/WCFTutorialpart02.zip

Friday 25 March 2011

WCF tutorial part 01

In this tutorial I would like to tell you a bit about WCF. WCF stands for Windows Communication Foundation and it's a part of .NET since 3.0 version. It allows us to both create and consume services.
We can communicate through HTTP, TCP, PIPES, PEER Network and MSMQ. It can be hosted in several modes:
  • Self hosting
  • Windows Service
  • IIS
  • WAS
All communication within WCF occurs through enpoints. Each endpoint can be described using ABC's:
  • A - Address - specifies where the endpoint can be found
  • B - Binding - specifies how a client can communicate with the endpoint
  • C - Contract - specifies which operations are available for the endpoint.
In this tutorial we will communicate through HTTP and service will be self-hosted (standalone .exe file).
We will use WSHttpBinding for endpoint.

Creating host
Let's begin with creating new project - Console application
Add new class file  IService.cs instead of a defined class we will write interface definition
interface IService
{
 string GetTime();
 string Greet(string name);
} 
Add another class called Service.cs implementing IService interface
class Service : IService
{
 public string GetTime()
 {
  return DateTime.Now.ToShortTimeString();
 }
 public string Greet(string name)
 {
  return "Hello " + name;
 }
}
Add reference to System.ServiceModel to project:

Add “using System.ServiceModel;” statement to IService.cs and mark our interface with attributes:

[ServiceContract]
interface IService
{
[OperationContract]
string GetTime();
[OperationContract]
string Greet(string name);
}
 
Create host with this lines:

Uri baseAddress = new Uri("http://localhost:8000/Service");
ServiceHost serviceHost = new ServiceHost(typeof(Service), baseAddress);

Add “using System.ServiceModel;” statement

Create first endpoint
serviceHost.AddServiceEndpoint(typeof(IService),new WSHttpBinding(),"Service");
As I mentioned before, an endpoint must consist of address, binding and contract, here we are specifing these three as following:
Address - "Service"
Binding - WSHttpBinding
Contract - IService

Create service metadata (so our service can be discovered):
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(smb);

Start host
serviceHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <enter> to terminate service.");
Console.ReadLine();
serviceHost.Close();


Whole file:
class Host
{
 static void Main(string[] args)
 {
  Uri baseAddress = new Uri("http://localhost:8000/Service");
  ServiceHost serviceHost = new ServiceHost(typeof(Service), baseAddress);
  try
  {
   serviceHost.AddServiceEndpoint(
   typeof(IService),
   new WSHttpBinding(),
   "Service");

   ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
   smb.HttpGetEnabled = true;
   serviceHost.Description.Behaviors.Add(smb);

   serviceHost.Open();
   Console.WriteLine("The service is ready.");
   Console.WriteLine("Press <enter> to terminate service.");
   Console.ReadLine();

   serviceHost.Close();
  }
  catch (CommunicationException)
  {
   if (serviceHost != null)
   {
    serviceHost.Abort();
   }
  }
  catch (Exception)
  {
   if (serviceHost != null)
   {
    serviceHost.Abort();
   }
   throw;
  }
 }
}

Creating client
Add new project Console Application Client
Right click on the solution and choose "Set Startup Projects...", in the new windows choose "Current selection"
Start your host by clicking inside Host project and press CTRL + F5. If everything have been done correctly you should get window saying:

Now rightclick on your client project and choose "Add Service Reference", inside the window as an address type an address of our endpoint ("http://localhost:8000/service") and cllick Go. Our service should be discovered.
Set Namespace to "ServiceReference" (as shown on the picture above) and click OK.
App.config file will be generated, reference to “System.ServiceModel” also will be added automatically.

We can start connecting to our host:
ServiceReference.ServiceClient client = new ServiceReference.ServiceClient();
Console.WriteLine(client.GetTime());
Console.WriteLine(client.Greet("anonymous"));
client.Close();

Click on Client project, and press CTRL+F5, if everything was done ok console window should open (last message is in polish)

One final note, inside app.config file in endpoint section there will be added line specifying identity:
<client>
    <endpoint address="http://localhost:8000/Service/Service" binding="wsHttpBinding"
        bindingConfiguration="WSHttpBinding_IService" contract="ServiceReference.IService"
        name="WSHttpBinding_IService">
        <identity>
            <userPrincipalName value="tomaszo@abcd.pl" />
        </identity>
    </endpoint>
</client>
If you have errors running client, remove the following line:
<identity>
    <userPrincipalName value="tomaszo@abcd.pl" />
</identity>
You can download whole project from here:
http://sites.google.com/site/terespl/files/WCFTutorialpart01.zip

Thursday 10 March 2011

Howto use custom form for my custom content type

Today I needed to use custom form for New and Edit Action for a specified content type, here's how I've done that. As you can see, at the end I added XmlDocuments section and there I pointed to my form. The reason I have to done it that way is the fact, I needed to hide column "FileLeafRef" from user (it was done with javascript on my custom form).

<ContentType
ID="0x012000D58488ADD1F448949BF8127D3AB6699C"
Name="My name"
Description="My description"
Group="My Group"
>
<folder TargetName="_cts/Requests"/>
<fieldrefs>
<fieldref ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" DisplayName="Numer zgłoszenia" ShowInNewForm="FALSE" ShowInEditForm="FALSE" />
<fieldref ID="{8553196d-ec8d-4564-9861-3dbe931050c8}" Name="FileLeafRef" Required="FALSE" ShowInNewForm="FALSE" ShowInEditForm="FALSE" ReadOnly="TRUE" />
</FieldRefs>
<xmldocuments>
<xmldocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
<formurls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
<new>_layouts/Layouts/NewEditForm.aspx</New>
<edit>_layouts/Layouts/NewEditForm.aspx</Edit>
</FormUrls>
</XmlDocument>
</XmlDocuments>
</ContentType>

Saturday 5 February 2011

Can't add button to a ribbon

I was having problem adding a button to the ribbon. I've done this before and had no problem so I was kind of stuck. I checked if the definition in appropriate element.xml file was correct - and it was, however my previous custom action on another list was working fine. It turned out, that the feature adding "Custom actions" had a scope of "Web" and it wasn't active on this particular web. Problem solved :)

Friday 4 February 2011

Configuring permissions on a list with powershell

Little of code:

$URL = "http://foo.bar" 
$web = Get-SPWeb -identity $URL/Workers/AbsenceReport
$list = $web.Lists["Absence report"]
$group = $web.SiteGroups["Visitors of the web"]
$assignment = new-object Microsoft.SharePoint.SPRoleAssignment($group)
$assignment.RoleDefinitionBindings.Add($web.RoleDefinitions["Contribute"])
$list.BreakRoleInheritance($true)
$list.RoleAssignments.Add($assignment)
$list.Update()


one thing: role definitions are localized, so in polish it isn't "Contribute" but "Współtworzenie"

Thursday 3 February 2011

Showing / hiding field depending on another field

I needed this kind of functionality:
I decide to use jQuery for this functionality. Here's how it's done:

1) jQuery was added to styles library through module

2) in my custom form in "AdditionalPageHead" following was added:
<script src="/Style Library/Scripts/jquery-1.5.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $("nobr:contains('Cel ')").append('<span title="This field is required" class="ms-formvalidation">*</span>');
            HideFields();
            AddEvent();
        });
        function HideFields() {
            $("nobr:contains('Cel ')").closest('tr').hide();
        }

        function getQueryString() {
            var assoc = new Array();
            var queryString = unescape(location.search.substring(1));
            var keyValues = queryString.split('&');
            for (var i in keyValues) {
                var key = keyValues[i].split('=');
                assoc[key[0]] = key[1];
            }
            return assoc;
        }

        function AddEvent() {
            var tmp = $("nobr:contains('Typ ')").closest('td').next().children('span:first').children('select').each(function () {
                var type = this.type;
                var tag = this.tagName.toLowerCase();
                if (tag == 'select') {
                    $(this).change(function () {
                        $("nobr:contains('Cel ')").closest('tr').toggle();
                    });
                }
                var fieldsetName = $(this).val();
                if (fieldsetName != 'Prywatne') {
                    $("nobr:contains('Cel ')").closest('tr').show();
                }
            });
        }
    </script>

Basically I'm getting things done in three steps:
1) add an asteriks mark to mark field as required (although I'm validating this through code)
2) hide field "Cel (tylko dla służbowych)"
3) if different option was selected inside "select" - show or hide hidden field

Monday 10 January 2011

Finding control inside repeater's footer

Recently I needed to get a value from a textbox inside a FooterTemplate in the OnClick event of a button. My first thought was to loop through the items-property on my repeater, but it only included the actual databound items, not the footer-item.
aspx.cs:
<asp:Repeater ID="Repeater1" runat="server">
        <ItemTemplate>
                Item
        </ItemTemplate>
        <FooterTemplate>
                Footer
                <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        </FooterTemplate>
</asp:Repeater>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />

Right way to do that was this way:
RepeaterItem riFooter=Repeater1.Controls[Repeater1.Controls.Count-1] as RepeaterItem;
if (riFooter != null && riFooter.ItemType == ListItemType.Footer) {
    TextBox TextBox1 = riFooter.FindControl("TextBox1") as TextBox;
    if (TextBox1 != null) {
        TextBox1.Text = "Test";
    }
}