Fixing Missing NuGet Packages

I have encountered this problem more than one time. Somehow, maybe when merging changes between branches, there are references in .NET projects to assemblies in NuGet packages that are not present in packages.config, which in turn can result in issues when updating packages to later versions. I put together a PowerShell script to detect this issues. It searches all .csproj files in subfolders to the current one.

# Get reference hintpath to packages:
$pattern = "<HintPath>.*Packages\\(?<id>(?:[a-zA-Z]+\.?)+)\.(?<version>(?:\d+\.)+\d+)\\.*</HintPath>"

Get-ChildItem -Path . -Filter "*.csproj" -File -Recurse | foreach {
    $projFilename = $_.FullName
    Write-Output "`r`n*** $projFilename ***"
    $packageFilename = "$($_.DirectoryName)\packages.config"
    if ([System.IO.File]::Exists($packageFilename))
    {
        $projtext = Get-Content -Path $projFilename
        $projtext | foreach {
            if ($_ -imatch $pattern)
            {
                $id = $Matches.Item("id")
                $version = $Matches.Item("version")
                Write-Output "$($Matches[0])"
                $foundInPackages = Select-String -Pattern "id=""$id"" version=""$version""" -Path $packageFilename -Quiet
                if ($foundInPackages) {
                    Write-Output (Select-String -Pattern "id=""$id"" version=""$version""" -Path $packageFilename).Line
                } else {
                    Write-Warning "Not found in package file!"
                }
            }
        }
    } else {
        Write-Warning "There is no package file at $packageFilename!"
    }
}
Advertisements

Windows Phone 7 Development in the year 2015

You want your Windows Phone app to work on Windows Phone 8.1, 8.0 and 7.1, right? In that case, you must create a Windows Phone 7.1 project in Visual Studio. You cannot do that with Windows Phone SDK 8.1 and Visual Studio 2013, but you don’t have to go back to using Windows Phone SDK 7.1 and Visual Studio 2010 either. Take the middle way, and install Visual Studio 2012 and Windows Phone SDK 8.0.

Modifying Installation Directory Security with Windows Installer

I had a ill-behaved application for which I needed to construct an MSI installation package. The problem with this application is that it requires users to have modify permissions on the installation folder (and subfolders), since it writes application data there.

So the first step was to create a custom action. Create a C# project, then Add New Item and choose the Installer Class template.

Here is the beginning of this class:

    [RunInstaller(true)]
    public partial class ClientInstaller : System.Configuration.Install.Installer
    {
        public ClientInstaller()
        {
            InitializeComponent();
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
            SetDirectorySecurity();
        }

Then, right-click on the setup project, choose View –> Custom actions to display the custom actions window. In the Install folder, add Primary output from the C# project.

The first problem was how to get hold of the installation folder. I used a context parameter, targetdir, for this.
string targetdir = Path.GetDirectoryName(Context.Parameters["targetdir"]);
This parameter needs to be set using the CustomActionData property. In the custom actions window, select primary output from the C# project, and set the CustomActionData property to
/targetdir="[TARGETDIR]\"
Yes, the double quotation marks and the backslash are needed.

The second problem was how to actually add the permissions. I found (part of) the answer in a forum post by “Jaso”: http://www.aspnet-answers.com/microsoft/NET-Security/30001760/how-to-change-group-permissions-on-existing-folder.aspx. The  problem with this code is that the statement “So just use ‘objectinherit and the child objects (even created at a later time in sub directories) inherit the permission correctly.” is false. You need to use both ObjectInherit and ContainerInherit to make sub folders inherit the same permission. Here is my complete SetDirectorySecurity:

        private void SetDirectorySecurity()
        {
            string targetdir = Path.GetDirectoryName(Context.Parameters["targetdir"]);
            Log("Adding modify rights for " + targetdir);
            // The following code was copied (and modified) from "Jaso" (http://www.aspnet-answers.com/microsoft/NET-Security/30001760/how-to-change-group-permissions-on-existing-folder.aspx).
            // Retrieve the Directory Security descriptor for the directory
            var dSecurity = Directory.GetAccessControl(targetdir, AccessControlSections.Access);
            // Build a temp domainSID using the Null SID passed in as a SDDL string.
            // The constructor will accept the traditional notation or the SDDL notation interchangeably.
            var domainSid = new SecurityIdentifier("S-1-0-0");
            // Create a security Identifier for the BuiltinUsers Group to be passed to the new accessrule
            var ident = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, domainSid);
            // Create a new Access Rule.
            // ContainerInherit AND ObjectInherit covers both target folder, child folder and child object.
            // However, when using both (combined with AND), the permissions aren't applied.
            // So use two rules.
            // Propagate.none means child and grandchild objects inherit.
            var accessRule1 = new FileSystemAccessRule(ident, FileSystemRights.Modify, InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow);
            var accessRule2 = new FileSystemAccessRule(ident, FileSystemRights.Modify, InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow);
            // Add the access rules to the Directory Security Descriptor
            dSecurity.AddAccessRule(accessRule1);
            dSecurity.AddAccessRule(accessRule2);
            // Persist the Directory Security Descriptor to the directory
            Directory.SetAccessControl(targetdir, dSecurity);
            Log("Rights added.");
        }

        private void Log(string message)
        {
            Context.LogMessage(message);
            System.Diagnostics.Trace.WriteLine(message, "1177 client installer");
        }

Upgrading old Visual Studio Solutions

I recently had to upgrade some old Visual Studio 2003 (!) solutions and projects to Visual Studio 2010. I tried to do that just by opening the solution and let the conversion wizard to its job. I had some challenges with the web application projects, including the old style web services.

The first lesson was to delete the project.csproj.webinfo file, because it contains an invalid reference to the project file, e.g.

<VisualStudioUNCWeb>
    <Web URLPath = “http://localhost/ExportWS/ExportWS.csproj” />
</VisualStudioUNCWeb>

Since the web site hadn’t been created, this URL was invalid.

Then, after the conversion, in one solution, I got the following error when re-opening the solution:

The following Web projects must be converted to the new Web Site format. The conversion process will remove all source control binding and the project will not be under source control after migration.

And then:

One or more projects in the solution were not loaded correctly. Please see the Output Window for details.

The output window contained the following error:

Some of the properties associated with the solution could not be read.

It turned out that the solution file had been corrupted. There were two extra GlobalSections. First there were:

GlobalSection(TeamFoundationVersionControl) = preSolution
    SccNumberOfProjects = 12
    …
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
    Debug|Any CPU = Debug|Any CPU
    Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
    …
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
    HideSolutionNode = FALSE
EndGlobalSection

But then, were were two extra GlobalSections:

GlobalSection(TeamFoundationVersionControl) = preSolution
    SccNumberOfProjects = 12
   …
EndGlobalSection
GlobalSection(TeamFoundationVersionControl) = preSolution
    …
EndGlobalSection

After removing these using Notepad, the above errors went away.

In another solution, each time I opened it I got a dialog saying the web projects must be converted to the new format. I found the solution here: http://connect.microsoft.com/VisualStudio/feedback/details/334842/repeated-conversion-of-project-file