DevOps cultuur, wensen en technologie komen samen

Organisaties veranderen continue, het weken lang werken aan één applicatie en aan het einde opleveren naar de productie omgeving is niet meer van deze tijd. Tegenwoordig worden de behoeftes om “Time to Market” te versnellen en het continue uitleveren van nieuwe software steeds belangrijker. Twee populaire voorbeelden van DevOps zijn bijvoorbeeld Facebook en Office365 waar continue op dagelijkse basis wijzigingen aan het platform worden toegevoegd of bijgewerkt.

Om dit proces te kunnen ondersteunen moet een aantal factoren zijn ingeregeld.
website_DevOps_maingraphic

1 Plannen
2 Ontwikkelen
3 Testen
4 Deployment voorbereiden
5 Releasen
6 Feedback ontvangen
7 Optimaliseren
8 Meten

Tijdens het ontwikkel proces van een software applicatie wordt in de analyse fase functionaliteiten beschreven in een product backlog, door ontwikkelt, getest en opgeleverd. Tot zover nog niet heel veel nieuws, echter onderscheid DevOps zich door het verder kunnen meten en monitoren van de applicatie. Met de klant in gesprek om Feedback te verzamelen over de geleverde functionaliteit en het meten van de applicatie. Na een aantal weken is er inzage of er moet worden bijgestuurd of dat de functionaliteit volledig naar wens is. De omvang van functionaliteiten zijn overzichtelijk waardoor de applicatie snel in gebruik genomen kan worden.

itoperationdev
DevOps bevat het proces om ervoor te kunnen zorgen dat “Afdelingen” samen gaan werken. DevOps implementeren in uw organisatie zorgt ervoor dat mensen die onderdeel uit maken van projecten operationele kennis vergaren door samen te werken met de beheerorganisatie. Vanuit de projectenorganisatie worden nieuwe technologieën en kennis terug geleverd aan de beheerorganisatie . Op deze manier kan de samenwerking binnen de totale organisatie worden versterkt.

In traditionele ICT bedrijven zijn de bekende kreten als “het is over de schutting gegooid”, systemen zijn niet goed overgedragen een helaas vaak voorkomend probleem. DevOps zorgt voor een dusdanige Cultuur en mindset verandering dat het verschil tussen project en beheer kleiner wordt of zelfs verdwijnt.

544-devops

Tooling
Microsoft pretendeert alle tooling in huis te hebben om zowel “On-Premise” als “Cloud applicaties” te kunnen uitvoeren in het DevOps proces. Visual Studio met Team Foundation server in combinatie met Azure Services fungeren als hoofdrol in het kunnen uitvoeren in de vorm van een DevOps trajecten.

cloudtools

DevOps beschrijft werkzaamheden vanuit de Infrastructuur om tijdens de uitvoering meer te automatiseren en het vastleggen van versiebeheer over de infrastructuur. Het maken van Load testen, Unit testen en het volledige geautomatiseerd testen zijn hier zeker onderdeel van.

SharePoint 2013 On-premise reorder userprofile property page drag and drop

The order property control in SharePoint 2013 isn’t user friendly. I have a solution to ordering the SharePoint 2013 profile fields for on-premise with a drag and drop.

userprofile

okbutton

With a application page and the right rightss to write properties in the userprofile page can you drag and drop in your own portal. No central administration needed.

Files there are created:
– Create a SharePoint 2013 Farm Project
– Added a svc service this service write the order in property bag of the SharePoint site. This way is it posible to save a “concept version” when you use the “OK” button to save the userprofile service.

try
            {
                SPSecurity.RunWithElevatedPrivileges(() =>
                {
                    using (var site = new SPSite(GetSiteUrl()))
                    {
                        site.AllowUnsafeUpdates = true;
                        site.RootWeb.AllowUnsafeUpdates = true;
                        site.RootWeb.AllProperties[“ProfileSortOrder”] = item;
                        site.RootWeb.Update();
                    }
                });
            }
            catch
            {
            }

the javascript part

<link rel=”stylesheet” href=”http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/themes/redmond/jquery-ui.css” type=”text/css” media=”all” />

    <script src=”http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js” type=”text/javascript”></script>

    <script src=”http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.min.js”
            type=”text/javascript”></script>

    <script type=”text/javascript”>

        $(function() {
            $(‘#sortable’).sortable({
                placeholder: ‘ui-state-highlight’,
                update: OnSortableUpdate
            });
            $(‘#sortable’).disableSelection();

            var progressMessage = ‘Saving changes…’;
            var successMessage = ‘Saved successfully!’;
            var errorMessage = ‘There was some error in processing your request’;
            var messageContainer = $(‘#message’).find(‘p’);

            function OnSortableUpdate(event, ui) {
                var order = $(‘#sortable’).sortable(‘toArray’).join(‘,’).replace(/id_/gi, ”);

                messageContainer.html(progressMessage);
                var serviceUri = “/_vti_bin/WVProfileOrder/UpdateProfileService.svc/SaveItems”;

                $.ajax({
                    type: ‘POST’,
                    url: serviceUri,
                    data: JSON.stringify(order),
                    contentType: ‘application/json; charset=utf-8’,
                    dataType: ‘json’,
                    success: OnSortableUpdateSuccess,
                    error: OnSortableUpdateError
                });
            }

            function OnSortableUpdateSuccess(response) {
                if (response != null) {
                    messageContainer.html(successMessage);
                }
            }

            function OnSortableUpdateError(xhr, ajaxOptions, thrownError) {
                messageContainer.html(errorMessage);
            }

        });

    </script>

 

The control

<asp:ListView ID=”ItemsListView” runat=”server” ItemPlaceholderID=”myItemPlaceHolder”>
           <LayoutTemplate>
           </LayoutTemplate>
           <LayoutTemplate>
               <asp:PlaceHolder ID=”myItemPlaceHolder” runat=”server”></asp:PlaceHolder>
           </LayoutTemplate>
           <ItemTemplate>
               <li class=”<%# Eval(“cssClass”) %>” id=’id_<%# Eval(“ItemID”) %>|<%# Eval(“ItemName”) %>|<%# Eval(“SectionDisplay”) %>’>
                   <%# Eval(“DisplayName”) %> – <%# Eval(“ItemName”) %> </li>
           </ItemTemplate>
       </asp:ListView>

 

site.AllowUnsafeUpdates = true;
                        site.RootWeb.AllowUnsafeUpdates = true;
                        SPContext.Current.Web.AllowUnsafeUpdates = true;
                        SPServiceContext context = SPServiceContext.GetContext(site);
                        var upcm = new UserProfileConfigManager(context);
                        int count = 0;

                        ProfileSubtypePropertyManager pcolEmployee =
                            upcm.ProfilePropertyManager.GetProfileSubtypeProperties(profileTypeName);
                        ArrayList allProps = pcolEmployee.PropertiesWithSection;
                        foreach (ProfileSubtypeProperty property in allProps)
                        {
                            if (!property.TypeProperty.IsVisibleOnEditor && !property.TypeProperty.IsVisibleOnViewer)
                            {
                                continue;
                            }
                           
                            try
                            {
                                item = new WvReOrderItem();
                                if (property.IsSection)
                                {
                                    item.SectionDisplay = true;
                                    item.CssClass = “ui-state-highlight”;
                                }
                                else
                                {
                                    item.SectionDisplay = false;
                                    item.CssClass = “ui-state-default”;
                                }

                                item.ItemID = count;
                                item.ItemName = property.Name;
                                item.ReOrderType = profileTypeName;
                                item.DisplayName = property.DisplayName;
                                items.Add(item);
                                count++;
                            }
                            catch (Exception exception)
                            {
                            }

I hope that this example helps you in the correct way, would you lik to have a example contact me at the contact information about this blog.

Use SharePoint 2013 with Less (Dynamic Style Sheet) (on-premise)

My Experience is when I build custom solutions with SharePoint 2013 that the design manager “Out-of-the-box” made design are easy. When I build a custom web part with custom style class to fix my design issues in a custom style sheet. The behavior is that when an administrator change the design that I used within my custom css file are not changed.

I have fixed this issue with .less.

version one Theme01:

image

version two Theme02:

image

I have nothing changed in my code, only change the theme and reset the MasterPage. My custom WebPart restyled the custom style automatically.

The output result in my HTML file are:

<script>
less.modifyVars({
‘@DisabledLines’: ‘rgba(58,86,96,1)’
});
</script>

The Software Architecture

image

The library I used for this is:
jquery-1.11.0.min.js
less-1.3.3.min.js

The instructure change iis manage has .less not as default mime type. you can use this commando with PowerShell to add this on every server in the farm.

add-webconfigurationproperty //staticContent -name collection -value @{fileExtension=’.less’; mimeType=’text/css’}

—————————————————————————————————–

We started with the SPColor file. The DisabledText has an value B1B1B1. We would like to use the color in the .less file on the client library.

<?xml version=”1.0″ encoding=”utf-8″?>
<s:colorPalette isInverted=”false” previewSlot1=”BackgroundOverlay” previewSlot2=”BodyText” previewSlot3=”AccentText” xmlns:s=”http://schemas.microsoft.com/sharepoint/”&gt;
<s:color name=”DisabledText” value=”B1B1B1″ />

——————————————————————————————————

This methode get the color from the default spcolorfile. SharePoint overwrite everytime with an apply the default spcolor file. When you use this, you get the new colors from the site theme.

public static string GetColorCodeFromSpColorFile(SPSite site, string staticColorName)
{
    SPFile file = site.RootWeb.GetFile(site.RootWeb.ThemedCssFolderUrl + “/theme.spcolor”);

var color = SPColor.Open(file);
byte r = color.Colors[staticColorName].DefaultColor.R;
byte g = color.Colors[staticColorName].DefaultColor.G;
byte b = color.Colors[staticColorName].DefaultColor.B;
byte a = color.Colors[staticColorName].DefaultColor.A;
decimal alpha = decimal.Round((decimal) a/(decimal) 255, 2);
return string.Format(“rgba({0},{1},{2},{3})”, r, g, b, alpha.ToString().Replace(“,”,”.”));

}

——————————————————————————————————–

Best Practice is here to reuse the names that are used in the color file.

DisabledLines = SPThemeControlHelper.GetColorCodeFromSpColorFile(site, ColorFileContstants.ColorConstDisabledLines);

——————————————————————————————————-

In the master file head put the this code before reference the library.

<script>
less = {
async: false,
fileAsync: false,
dumpLineNumbers: “comments”,
relativeUrls: false
};
</script>

<script type=”text/javascript” src=”/_layouts/15/ProjectName/less-1.3.3.min.js”></script> ( we use an old library compatibility )

——————————————————————————————————–

Control to load in masterpage

<script>
less.modifyVars({
‘@DisabledLines’: ‘<%= DisabledLines %>’
});
</script>

.less file
/* Footer */
#footer {
background-color: @DisabledLines;
position:relative;
clear:both;
}

SharePoint 2013: use active directory in combination with SharePoint

this article is also used for SharePoint 2010

I have made a reference to:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\System.DirectoryServices.AccountManagement.dll

var users = new List<User>();

                    // set up domain context
                    var ctx = new PrincipalContext(
                        ContextType.Domain,
                        “Domain\\”,
                        “jordy.vanpaassen”,
                        “P@sswordonlyfordemo”);

                    // find the group you’re interested in
                    GroupPrincipal myGroup = GroupPrincipal.FindByIdentity(ctx, userOrGroupName);

                    // if you found it – get its members
                    if (myGroup != null)
                    {
                        // if your call the GetMembers, you can optionally specify a “Recursive” flag – done here
                        PrincipalSearchResult<Principal> allMembers = myGroup.GetMembers(true);
                       
                        foreach (UserPrincipal allMember in allMembers.Cast<UserPrincipal>().Where(allMember => allMember.EmailAddress != null))
                        {
                            user.EmailAddress = allMember.EmailAddress;
                            user.UserType = type;
                            user.Name = allMember.Name;
                            user.SamAccountName = allMember.SamAccountName;
                            users.Add(user);
                        }
                    }

                    ctx.Dispose();

 

/// <summary>
    /// The user class the bind different type of users.
    /// </summary>
    public class User
    {
        #region Public Properties

        /// <summary>
        /// Gets or sets the email address.
        /// </summary>
        public string EmailAddress { get; set; }

        /// <summary>
        /// Gets or sets The Name property.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the sam Id.
        /// </summary>
        public string SamAccountName { get; set; }

        /// <summary>
        /// Gets or sets The user type property.
        /// </summary>
        public string UserType { get; set; }

        #endregion
    }

SharePoint 2013 Principal Type from a User, Active Directory or SharePoint Group

this article is also ready for SharePoint 2010 on-premise, not available on Office 365 at the moment on this way.

We would like to have a function to check what the principal type of a people picker, we made a demo code to do this.  see:

//The code block write the information about your principal type. ( SharePoint Group, SharePoint User of Active directory user )
            //This code block is only allowed in full trust SharePoint solutions. This is not ready for SharePoint Online.
            //The reason is that the SPUtility.ResolvePrincipal only for full trust solutions.
            using (SPSite site = new SPSite(SPContext.Current.Site.ID))
            {
                using (SPWeb web = site.OpenWeb(site.RootWeb.ID))
                {
                    var principalInfo = SPUtility.ResolvePrincipal(web, web.CurrentUser.LoginName, SPPrincipalType.All, SPPrincipalSource.All, null, false);
                    Label label = new Label();
                    label.Text += string.Format(“Security Type: {0}”, principalInfo.PrincipalType.ToString());
                    this.Controls.Add(label);
                }
            }

the result of this code block in a simpel webpart is:

Capture

the yellow selection is the loginname this can be also the name of the sharepoint group or active directory group

Write a custom Audience Field to a WebPart ToolPart for SharePoint

note: SharePoint 2013 ready, this is written for version SharePoint 2010

Audiences in SharePoint are simple to use. For example: you can make a active directory group and put the write users in this group. For example the department Finance. You can bind this group to SharePoint and its show only the people of the department finance for example. It is not a security provider but a filter system.

When you installed SharePoint and you use the audience field of a SharePoint ToolPart. It shows the WebPart when you a user in the group and hide the content when you not in the group.

The functionality what we would have is that we show other content when you are NOT in the selected audience. We choose to create another custom audience editor field on the ToolPart. You can do this with this control.

AudienceEditor ( for more information on msdn: http://msdn.microsoft.com/en-us/library/microsoft.office.server.webcontrols.audienceeditor(v=office.14).aspx )

We used this code to create the ToolPart:
//create the editor
this.audienceEditor = new AudienceEditor();
//This is a flag, when you put this three types in the editor you have the same as
//the default of SharePoint.
this.audienceEditor.Types = AudienceEditor.AudienceType.GlobalAudience | AudienceEditor.AudienceType.DL | AudienceEditor.AudienceType.SharePointGroup;

//the label for the editor field on the ToolPart.
this.audienceEditor.Text = “target Filter”

//Add this control to the ToolPart.
this.Controls.Add(this.audienceEditor);

In the WebPart file we used this code:
if (this.IfAudience())
            {
                  this.label.Text = “standard filter”;
                  base.CreateChildControls();
            }
            else
            {
                 this.label.Text = “department filter”;
             }

       /// <summary>
        /// Gets or sets specific category.
        /// </summary>
        [Personalizable(PersonalizationScope.Shared)]
        [DefaultValue(“”)]
        public string TargetGroupFilter
        {
            get
            {
                var value = this.ViewState[“TargetGroupFilter”];

                if (value == null)
                {
                    return string.Empty;
                }

                return value.ToString();
            }

            set
            {
                this.ViewState[“TargetGroupFilter”] = value;
            }
        }

public bool IfAudience()
        {
            if (!string.IsNullOrEmpty(this.TargetGroupFilter))
            {
                if (ServerContext.Current != null)
                {
                    AudienceLoader audienceLoader = AudienceLoader.GetAudienceLoader();
                    return !AudienceManager.IsCurrentUserInAudienceOf(audienceLoader, this.TargetGroupFilter, false);
                }
            }
            else
            {
                return false;
            }

            return false;
        }

Result:
audience field

The picker and the editor field.