replace highlights

This commit is contained in:
2020-09-24 19:50:41 -05:00
parent a80ae21fd2
commit 769a640e2e
39 changed files with 180 additions and 180 deletions

View File

@@ -12,9 +12,9 @@ Turns out none of the “regular” methods really work. The Trim function only
You have to use the Chr(13) or Chr(10) functions to actually get the character values for the newline characters. So, my solution looked like this: You have to use the Chr(13) or Chr(10) functions to actually get the character values for the newline characters. So, my solution looked like this:
{% highlight csharp %} ```csharp
Replace(Replace(stringVariable, Chr(10), ), Chr(13), ) Replace(Replace(stringVariable, Chr(10), ), Chr(13), )
{% endhighlight %} ```
Thanks to this forum post for providing the clues: Thanks to this forum post for providing the clues:
[http://www.daniweb.com/forums/thread54797.html](http://www.daniweb.com/forums/thread54797.html) [http://www.daniweb.com/forums/thread54797.html](http://www.daniweb.com/forums/thread54797.html)

View File

@@ -10,9 +10,9 @@ I try to avoid setting styles in my code as much as possible. However, I ran acr
The particular border I needed is the ContentStyle.Border border of the ASPxPageControl and I needed to set the BorderColor property which is a System.Drawing.Color object. There isnt any straightforward way to get a Color object from a hexadecimal color using the Color object itself. You have to use the ColorTranslator (also in the System.Drawing namespace) which gives you a FromHtml method and returns the correct Color object. The particular border I needed is the ContentStyle.Border border of the ASPxPageControl and I needed to set the BorderColor property which is a System.Drawing.Color object. There isnt any straightforward way to get a Color object from a hexadecimal color using the Color object itself. You have to use the ColorTranslator (also in the System.Drawing namespace) which gives you a FromHtml method and returns the correct Color object.
{% highlight csharp %} ```csharp
Color hexColor = ColorTranslator.FromHtml(#666666); Color hexColor = ColorTranslator.FromHtml(#666666);
{% endhighlight %} ```
Thanks to this guy for the quick answer: Thanks to this guy for the quick answer:
[http://www.akxl.net/labs/articles/converting-a-hexadecimal-color-to-a-system.drawing.color-object/](http://www.akxl.net/labs/articles/converting-a-hexadecimal-color-to-a-system.drawing.color-object/) [http://www.akxl.net/labs/articles/converting-a-hexadecimal-color-to-a-system.drawing.color-object/](http://www.akxl.net/labs/articles/converting-a-hexadecimal-color-to-a-system.drawing.color-object/)

View File

@@ -12,14 +12,14 @@ One helpful way Ive been able to use post-build events is to copy the compile
Adding a post-build event couldnt be much simpler either. In Visual Studio just right-click on the project you want to add the post-build event for in Solution Explorer and select “Properties”. You can either do that or, with the project selected in Solution Explorer, hit Alt-Enter. The project properties window will display. On the left-hand side, click the “Build Events” tab. Youll see two boxes there. One is for pre-build events and one is for post-build events. Adding a post-build event couldnt be much simpler either. In Visual Studio just right-click on the project you want to add the post-build event for in Solution Explorer and select “Properties”. You can either do that or, with the project selected in Solution Explorer, hit Alt-Enter. The project properties window will display. On the left-hand side, click the “Build Events” tab. Youll see two boxes there. One is for pre-build events and one is for post-build events.
{% highlight text %} ```text
In the post-build events textbox add the following: In the post-build events textbox add the following:
IF NOT ($(ConfigurationName)) == (Debug) GOTO END IF NOT ($(ConfigurationName)) == (Debug) GOTO END
cd $(ProjectDir) cd $(ProjectDir)
copy /y bin\debug\*.dll C:\inetpub\wwwroot\wss\VirtualDirectories\{YOUR SHAREPOINT SITE DIRECTORY}\bin copy /y bin\debug\*.dll C:\inetpub\wwwroot\wss\VirtualDirectories\{YOUR SHAREPOINT SITE DIRECTORY}\bin
copy /y bin\debug\*.pdb C:\inetpub\wwwroot\wss\VirtualDirectories\{YOUR SHAREPOINT SITE DIRECTORY}\bin copy /y bin\debug\*.pdb C:\inetpub\wwwroot\wss\VirtualDirectories\{YOUR SHAREPOINT SITE DIRECTORY}\bin
:END :END
{% endhighlight %} ```
These are just basic Windows batch commands like youd find in any Windows batch file. This is a very basic setup, but it should be a good starting point for you to work from. All it does is check whether you are building with your Debug build configuration, if you are, then it moves to your project directory and copies the DLLs in your bin\debug folder to the bin folder of your SharePoint site. These are just basic Windows batch commands like youd find in any Windows batch file. This is a very basic setup, but it should be a good starting point for you to work from. All it does is check whether you are building with your Debug build configuration, if you are, then it moves to your project directory and copies the DLLs in your bin\debug folder to the bin folder of your SharePoint site.

View File

@@ -12,17 +12,17 @@ I successfully installed SharePoint 2010 and proceeded to run the configuration
Apparently, at some point in the process the configuration wizard looks for the serviceHostingEnvironment element under the `<system.serviceModel>` section in the Central Administration web.config. Apparently, at some point in the process the configuration wizard looks for the serviceHostingEnvironment element under the `<system.serviceModel>` section in the Central Administration web.config.
{% highlight xml %} ```xml
<serviceHostingEnvironment aspNetCompatibilityEnabled=”true” /> <serviceHostingEnvironment aspNetCompatibilityEnabled=”true” />
{% endhighlight %} ```
If it doesnt find it adds it itself, but curiously, it wraps it in an incomplete system.serviceModel tag so it looks like this: If it doesnt find it adds it itself, but curiously, it wraps it in an incomplete system.serviceModel tag so it looks like this:
{% highlight xml %} ```xml
<system.serviceModel> <system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled=”true” /> <serviceHostingEnvironment aspNetCompatibilityEnabled=”true” />
</system.serviceModel> </system.serviceModel>
{% endhighlight %} ```
This then caused the configuration wizard to bomb out. This then caused the configuration wizard to bomb out.

View File

@@ -10,7 +10,7 @@ We wanted an easy solution to open every document in a SharePoint from a documen
I dont know of any way to do this via a setting in SharePoint, but a little JavaScript employing jQuery does the job just perfectly. I dont know of any way to do this via a setting in SharePoint, but a little JavaScript employing jQuery does the job just perfectly.
{% highlight javascript %} ```javascript %}
$(document).ready( $(document).ready(
function () { function () {
// has to be on an interval for grouped doc libraries // has to be on an interval for grouped doc libraries
@@ -45,7 +45,7 @@ $(document).ready(
); );
} }
); );
{% endhighlight %} ```
This JavaScript takes into account that some Document Libraries are grouped and so not all the document links (or icon links) will appear on the page load. This is the reason for the half-second interval. At the most half a second after the group is expanded the newly loaded links will be altered to also open in a new window. This JavaScript takes into account that some Document Libraries are grouped and so not all the document links (or icon links) will appear on the page load. This is the reason for the half-second interval. At the most half a second after the group is expanded the newly loaded links will be altered to also open in a new window.

View File

@@ -8,12 +8,12 @@ tags: [command-line]
--- ---
I find myself often having to sanitize file names and paths because Im creating files from some kind of user input that Im unsure about. I found this handy way of doing this in one line today: I find myself often having to sanitize file names and paths because Im creating files from some kind of user input that Im unsure about. I found this handy way of doing this in one line today:
{% highlight text %} ```text
fileName = Path.GetInvalidFileNameChars().Aggregate(fileName, (name, c) => name.Replace(c, _)); fileName = Path.GetInvalidFileNameChars().Aggregate(fileName, (name, c) => name.Replace(c, _));
{% endhighlight %} ```
Note that the same goes for paths. The only thing that changes is the static method you use from Path: Note that the same goes for paths. The only thing that changes is the static method you use from Path:
{% highlight text %} ```text
filePath = Path.GetInvalidPathChars().Aggregate(filePath , (name, c) => name.Replace(c, _)); filePath = Path.GetInvalidPathChars().Aggregate(filePath , (name, c) => name.Replace(c, _));
{% endhighlight %} ```

View File

@@ -20,14 +20,14 @@ After some digging around and playing with Notepad++ (where I could switch the e
So, eventually, I came up with these few lines of code which convert the encoding of my text and fixed all of my problems. Woohoo! So, eventually, I came up with these few lines of code which convert the encoding of my text and fixed all of my problems. Woohoo!
{% highlight csharp %} ```csharp
Encoding targetEncoding = Encoding.GetEncoding(1252); Encoding targetEncoding = Encoding.GetEncoding(1252);
byte[] utf8Bytes = targetEncoding.GetBytes(text); byte[] utf8Bytes = targetEncoding.GetBytes(text);
byte[] ansiBytes = Encoding.Convert(Encoding.UTF8, byte[] ansiBytes = Encoding.Convert(Encoding.UTF8,
targetEncoding, targetEncoding,
utf8Bytes); utf8Bytes);
return targetEncoding.GetString(ansiBytes); return targetEncoding.GetString(ansiBytes);
{% endhighlight %} ```
What this simple code does is first get the Encoding for the ANSI character encoding (1252 is ANSI, apparently). It then gets the bytes of the string with the ANSI encoding, converts them from the ANSI encoding to UTF-8 encoding and then gets the string with the ANSI encoding. What this simple code does is first get the Encoding for the ANSI character encoding (1252 is ANSI, apparently). It then gets the bytes of the string with the ANSI encoding, converts them from the ANSI encoding to UTF-8 encoding and then gets the string with the ANSI encoding.

View File

@@ -14,8 +14,8 @@ In any case, the bug showed up when I had an existing overlay showing and wanted
## Solution ## Solution
While its somewhat of a hack, the best solution I found was to simply remove the div that Overlay creates with id “exposeMask” before I display the second overlay. While its somewhat of a hack, the best solution I found was to simply remove the div that Overlay creates with id “exposeMask” before I display the second overlay.
{% highlight text %} ```text
$(“#exposeMask”).remove(); $(“#exposeMask”).remove();
{% endhighlight %} ```
I believe this is what is happening: when the first overlay is closed by the library, it doesnt properly handle the existing exposeMask div and so when the second overlay shows it misunderstands the mask to be displaying properly and doesnt calculate its own display values properly. Therefore, its z-index is wrong (or non-existing) and the mask remains hidden (because the library hid it when it closed the first overlay). I believe this is what is happening: when the first overlay is closed by the library, it doesnt properly handle the existing exposeMask div and so when the second overlay shows it misunderstands the mask to be displaying properly and doesnt calculate its own display values properly. Therefore, its z-index is wrong (or non-existing) and the mask remains hidden (because the library hid it when it closed the first overlay).

View File

@@ -14,18 +14,18 @@ I knew the real solution had to be some type of command-line utility and a batch
First of all, I found HTML Tidy which I could run from the Windows command line to format a file. Using a configuration file for the tidy.exe (placed in the same directory as tidy.exe and named tidcfg.inialthough neither matters, see below) that looked like this: First of all, I found HTML Tidy which I could run from the Windows command line to format a file. Using a configuration file for the tidy.exe (placed in the same directory as tidy.exe and named tidcfg.inialthough neither matters, see below) that looked like this:
{% highlight text %} ```text
indent:yes indent:yes
indent-attributes:yes indent-attributes:yes
{% endhighlight %} ```
I got the formatting I wanted. I got the formatting I wanted.
Now, all I had to do was brush up on my Windows batch command skills to run tidy.exe on multiple files. Easy enough! This is what my batch file looked like: Now, all I had to do was brush up on my Windows batch command skills to run tidy.exe on multiple files. Easy enough! This is what my batch file looked like:
{% highlight text %} ```text
for /d %%X in (C:\<path_to_parent_directory>\*) do (c:\<path_to_tidy.exe>\tidy.exe -m -xml -config c:\<path_to_tidy.ini_file>\tidycfg.ini %%X\<xml_file_name>.xml) for /d %%X in (C:\<path_to_parent_directory>\*) do (c:\<path_to_tidy.exe>\tidy.exe -m -xml -config c:\<path_to_tidy.ini_file>\tidycfg.ini %%X\<xml_file_name>.xml)
{% endhighlight %} ```
I had a folder structure where there were hundreds of directories inside this one parent directory. Each of the child directories had a single XML file in it. Therefore, I needed the C:\<path_to_parent_directory>\* wildcard. I had a folder structure where there were hundreds of directories inside this one parent directory. Each of the child directories had a single XML file in it. Therefore, I needed the C:\<path_to_parent_directory>\* wildcard.

View File

@@ -28,13 +28,13 @@ This part is easy. Actually, all the parts are easy. You just need to know wha
1. Select your new template and click on the Edit button 1. Select your new template and click on the Edit button
1. In the Layout field (the XML that describes the player), add an Image element inside the Layout element. See the BEML reference documentationfor details. Here is what my Image element looks like: 1. In the Layout field (the XML that describes the player), add an Image element inside the Layout element. See the BEML reference documentationfor details. Here is what my Image element looks like:
{% highlight xml %} ```xml
<Image id="logoOverlay" <Image id="logoOverlay"
width="50" width="50"
height="50" height="50"
scaleMode="exactFit" scaleMode="exactFit"
visible="{!videoPlayer.menu.open}"/> visible="{!videoPlayer.menu.open}"/>
{% endhighlight %} ```
All of the attributes are optional except the id attribute. It doesnt have to be named “logoOverlay”, but you have to have something there. Notice the value for my “visible” attribute. This ensures that my logo disappears when the video is done and doesnt awkwardly overlay any of the video menu UI elements. Remove it if you want your logo to display the whole time. Also note the “x” and “y” values. Change these to your liking. You might have to wait to finish Step Two below when youve added a logo and then you can test a video with your player to see where the logo fits best. From there, you can keep adjusting your logo until youre satisfied. All of the attributes are optional except the id attribute. It doesnt have to be named “logoOverlay”, but you have to have something there. Notice the value for my “visible” attribute. This ensures that my logo disappears when the video is done and doesnt awkwardly overlay any of the video menu UI elements. Remove it if you want your logo to display the whole time. Also note the “x” and “y” values. Change these to your liking. You might have to wait to finish Step Two below when youve added a logo and then you can test a video with your player to see where the logo fits best. From there, you can keep adjusting your logo until youre satisfied.
1. Now click on All Players in the left sidebar and then click on the New Player button at the bottom 1. Now click on All Players in the left sidebar and then click on the New Player button at the bottom

View File

@@ -8,18 +8,18 @@ tags: [xslt]
--- ---
Lets say you have a simple XML document that looks something like this: Lets say you have a simple XML document that looks something like this:
{% highlight xml %} ```xml
<root> <root>
<Pod id="1"></Pod> <Pod id="1"></Pod>
<Pod id="2"></Pod> <Pod id="2"></Pod>
<Pod id="3"></Pod> <Pod id="3"></Pod>
<Pod id="4"></Pod> <Pod id="4"></Pod>
</root> </root>
{% endhighlight %} ```
The content or meaning of the pods is irrelevant. The idea is that you have a “list” of elements (pods in this case) in your XML. How, then, do you use XSLT to group these pods into rows of two, three or whatever number of pods across? Something like this: The content or meaning of the pods is irrelevant. The idea is that you have a “list” of elements (pods in this case) in your XML. How, then, do you use XSLT to group these pods into rows of two, three or whatever number of pods across? Something like this:
{% highlight xml %} ```xml
<div> <div>
<div class="row"> <div class="row">
<div class="pod"> pod 1 </div> <div class="pod"> pod 1 </div>
@@ -30,7 +30,7 @@ The content or meaning of the pods is irrelevant. The idea is that you have a
<div class="pod"> pod 4 </div> <div class="pod"> pod 4 </div>
</div> </div>
</div> </div>
{% endhighlight %} ```
This example would required three pods per row. The example XSLT below will work for any number of pods per row with a simple edit (explained below). This example would required three pods per row. The example XSLT below will work for any number of pods per row with a simple edit (explained below).
@@ -38,7 +38,7 @@ My first thought was from a very normal programmers perspective. Id use so
Turns out, it really isnt difficult. You just have to think a little differently and start using xsl:template, xsl:call-template and xsl:apply-templates effectively along with their select and match attributes. So, take a look at this XSLT file: Turns out, it really isnt difficult. You just have to think a little differently and start using xsl:template, xsl:call-template and xsl:apply-templates effectively along with their select and match attributes. So, take a look at this XSLT file:
{% highlight xml %} ```xml
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
@@ -76,7 +76,7 @@ Turns out, it really isnt difficult. You just have to think a little differen
<! whatever content your "pods" contain can be marked up here > <! whatever content your "pods" contain can be marked up here >
</xsl:template> </xsl:template>
</xsl:stylesheet> </xsl:stylesheet>
{% endhighlight %} ```
Heres whats going on: first, we call xsl:apply-templates on the first and then every third Pod using “Pod[position() mod 3 = 1]”. This will select the Pod at the start of every row: Pods 1 and 4. Notice that XSLT indexing starts at 1 and NOT 0. The PodRow template will match these selected Pods. Heres whats going on: first, we call xsl:apply-templates on the first and then every third Pod using “Pod[position() mod 3 = 1]”. This will select the Pod at the start of every row: Pods 1 and 4. Notice that XSLT indexing starts at 1 and NOT 0. The PodRow template will match these selected Pods.
@@ -89,7 +89,7 @@ I needed another feature from my XSLT though. I needed every last pod in each ro
I needed my HTML to look like this (notice the additional “last” class): I needed my HTML to look like this (notice the additional “last” class):
{% highlight xml %} ```xml
<div> <div>
<div class="row"> <div class="row">
<div class="pod"> pod 1 </div> <div class="pod"> pod 1 </div>
@@ -100,11 +100,11 @@ I needed my HTML to look like this (notice the additional “last” class):
<div class="pod last"> pod 4 </div> <div class="pod last"> pod 4 </div>
</div> </div>
</div> </div>
{% endhighlight %} ```
So, this is what I had to do: So, this is what I had to do:
{% highlight xml %} ```xml
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
@@ -157,7 +157,7 @@ So, this is what I had to do:
<! whatever content your "pods" contain can be marked up here > <! whatever content your "pods" contain can be marked up here >
</xsl:template> </xsl:template>
</xsl:stylesheet> </xsl:stylesheet>
{% endhighlight %} ```
This version of the XSLT functions exactly the same as the previous one. The only additions are for identifying the last pod in each row for all cases. So, here is what has changed. This version of the XSLT functions exactly the same as the previous one. The only additions are for identifying the last pod in each row for all cases. So, here is what has changed.

View File

@@ -12,14 +12,14 @@ I got caught today in a stupid problem. But, it wasnt obvious (at least to m
## Solution ## Solution
The solution was just correctly a stupid oversight on my part. I use ReSharper, so what I would do is just type the control prefix, colon then the name of the control and ReSharper would give me the suggestion to add the right Register tag. Well, ReSharper looks at it like a WebControl, not a UserControl. So, the Register tag is adds looks like this: The solution was just correctly a stupid oversight on my part. I use ReSharper, so what I would do is just type the control prefix, colon then the name of the control and ReSharper would give me the suggestion to add the right Register tag. Well, ReSharper looks at it like a WebControl, not a UserControl. So, the Register tag is adds looks like this:
{% highlight csharp %} ```csharp
<%@ Register TagPrefix="ogden" Namespace="Ogden.Web.controls" Assembly="Ogden.Web" %> <%@ Register TagPrefix="ogden" Namespace="Ogden.Web.controls" Assembly="Ogden.Web" %>
{% endhighlight %} ```
It should look like this: It should look like this:
{% highlight csharp %} ```csharp
<%@ Register TagPrefix="ogden" TagName="BlogComments" src="BlogComments.ascx" %> <%@ Register TagPrefix="ogden" TagName="BlogComments" src="BlogComments.ascx" %>
{% endhighlight %} ```
So, if youre dumb like me, make sure you have the right Register tag if youre nesting a UserControl (or using a UserControl anywhere really). So, if youre dumb like me, make sure you have the right Register tag if youre nesting a UserControl (or using a UserControl anywhere really).

View File

@@ -14,9 +14,9 @@ I found a great, compact solution on Stack Overflow here: [http://stackoverflow.
Heres the code I used to set a Repeater DataSource: Heres the code I used to set a Repeater DataSource:
{% highlight csharp %} ```csharp
PodsRepeater.DataSource = Data.Items PodsRepeater.DataSource = Data.Items
.Select((x, i) => new { Index = i, Value = x }) .Select((x, i) => new { Index = i, Value = x })
.GroupBy(obj => obj.Index / 4) .GroupBy(obj => obj.Index / 4)
.Select(obj => obj.Select(v => v.Value).ToList()); .Select(obj => obj.Select(v => v.Value).ToList());
{% endhighlight %} ```

View File

@@ -9,7 +9,7 @@ tags: [sitecore]
## Problem ## Problem
I got the error message (in my Firebug console) in the Sitecore Page Editor on a page where I had a nested sublayout. I had a basic two-column layout for the main sublayout of the page. Then, in the right column, I had another sublayout that further divided up the right column as I needed. Here is what the nested sublayout looked like: I got the error message (in my Firebug console) in the Sitecore Page Editor on a page where I had a nested sublayout. I had a basic two-column layout for the main sublayout of the page. Then, in the right column, I had another sublayout that further divided up the right column as I needed. Here is what the nested sublayout looked like:
{% highlight html %} ```html %}
<sc:Placeholder runat="server" Key="blogRightColumnTop"/> <sc:Placeholder runat="server" Key="blogRightColumnTop"/>
<div class="sidebar-blog"> <div class="sidebar-blog">
@@ -19,14 +19,14 @@ I got the error message (in my Firebug console) in the Sitecore Page Editor on a
<div class="sidebar-ads"> <div class="sidebar-ads">
<sc:Placeholder runat="server" Key="blogRightColumnBottomRight"/> <sc:Placeholder runat="server" Key="blogRightColumnBottomRight"/>
</div> </div>
{% endhighlight %} ```
This was a Javascript error that was preventing the Page Editor from fully loading the editor buttons for the edit frames I had on the page. This was a Javascript error that was preventing the Page Editor from fully loading the editor buttons for the edit frames I had on the page.
## Solution ## Solution
The error message (surprise, surprise) was a little mystifying, but it gave me enough of a clue to think that there was some type of nesting issue. I noticed that I had a sc:Placeholder element at the top of my nested sub-layout with nothing wrapping it. Perhaps this was the issue? I tried this edit to my nested sub-layout: The error message (surprise, surprise) was a little mystifying, but it gave me enough of a clue to think that there was some type of nesting issue. I noticed that I had a sc:Placeholder element at the top of my nested sub-layout with nothing wrapping it. Perhaps this was the issue? I tried this edit to my nested sub-layout:
{% highlight html %} ```html %}
<div> <div>
<sc:Placeholder runat="server" Key="blogRightColumnTop"/> <sc:Placeholder runat="server" Key="blogRightColumnTop"/>
@@ -38,6 +38,6 @@ The error message (surprise, surprise) was a little mystifying, but it gave me e
<sc:Placeholder runat="server" Key="blogRightColumnBottomRight"/> <sc:Placeholder runat="server" Key="blogRightColumnBottomRight"/>
</div> </div>
</div> </div>
{% endhighlight %} ```
Notice the single, wrapping div. This worked! So, Im not sure why, but apparently it solves this nesting problem. Perhaps Sitecore just does not expect a sc:Placeholder to be directly inside of another sc:Placeholder and so wrapping it solves that direct nesting issue. Notice the single, wrapping div. This worked! So, Im not sure why, but apparently it solves this nesting problem. Perhaps Sitecore just does not expect a sc:Placeholder to be directly inside of another sc:Placeholder and so wrapping it solves that direct nesting issue.

View File

@@ -14,18 +14,18 @@ Posts like this one [http://sharepoint.stackexchange.com/questions/41358/delete-
Here was my specific case. In my FeatureDeactivating method I was setting all the SPWebs back to the original v4.master like this: Here was my specific case. In my FeatureDeactivating method I was setting all the SPWebs back to the original v4.master like this:
{% highlight csharp %} ```csharp
foreach (SPWeb site in siteColl.AllWebs) foreach (SPWeb site in siteColl.AllWebs)
{ {
site.MasterUrl = masterUrl; site.MasterUrl = masterUrl;
site.CustomMasterUrl = masterUrl; site.CustomMasterUrl = masterUrl;
site.Update(); site.Update();
} }
{% endhighlight %} ```
Notice how I am looping through the SPSite.AllWebs SPWebCollection and updating each SPWeb after I reset the master page URLs. Now, here is what I was doing to try to delete the master page file from the _catalogs/masterpage library: Notice how I am looping through the SPSite.AllWebs SPWebCollection and updating each SPWeb after I reset the master page URLs. Now, here is what I was doing to try to delete the master page file from the _catalogs/masterpage library:
{% highlight csharp %} ```csharp
string fileUrl = SPUrlUtility.CombineUrl( string fileUrl = SPUrlUtility.CombineUrl(
siteColl.ServerRelativeUrl, siteColl.ServerRelativeUrl,
file.FullRelativeUrl); file.FullRelativeUrl);
@@ -39,21 +39,21 @@ try
} }
} }
catch { } catch { }
{% endhighlight %} ```
When I would get to the spFile.Delete() line, it would catch the exception whose error message is the title of this post. But why?? The master page wasnt being referenced anywhere anymore! As I would discover, the problem is on this line: When I would get to the spFile.Delete() line, it would catch the exception whose error message is the title of this post. But why?? The master page wasnt being referenced anywhere anymore! As I would discover, the problem is on this line:
{% highlight csharp %} ```csharp
SPFile spFile = siteColl.RootWeb.GetFile(fileUrl); SPFile spFile = siteColl.RootWeb.GetFile(fileUrl);
{% endhighlight %} ```
Do you see it? I didnt at first either. The RootWeb SPWeb reference isnt pointing to the same object that the same SPWeb in the SPSite.AllWebs collection is pointing to. So, technically, the RootWeb object still thinks its master page URLs are pointing to my custom master that Im trying to delete because it hasnt had Update() called on it. Do you see it? I didnt at first either. The RootWeb SPWeb reference isnt pointing to the same object that the same SPWeb in the SPSite.AllWebs collection is pointing to. So, technically, the RootWeb object still thinks its master page URLs are pointing to my custom master that Im trying to delete because it hasnt had Update() called on it.
To fix it, I had to get my SPFile from one of the SPWebs in SPSite.AllWebs, like this: To fix it, I had to get my SPFile from one of the SPWebs in SPSite.AllWebs, like this:
{% highlight csharp %} ```csharp
SPFile spFile = siteColl.AllWebs.First().GetFile(fileUrl); SPFile spFile = siteColl.AllWebs.First().GetFile(fileUrl);
{% endhighlight %} ```
That enables me to delete the file with no errors. That enables me to delete the file with no errors.
@@ -67,7 +67,7 @@ When iterating through SPWebs dispose of items with the using statement. This wi
So it might look like this: So it might look like this:
{% highlight csharp %} ```csharp
using(SPSite siteColl = properties.Feature.Parent as SPSite) using(SPSite siteColl = properties.Feature.Parent as SPSite)
{ {
foreach (SPWeb site in siteColl.AllWebs) foreach (SPWeb site in siteColl.AllWebs)
@@ -75,4 +75,4 @@ using(SPSite siteColl = properties.Feature.Parent as SPSite)
site.MasterUrl = masterUrl; site.CustomMasterUrl = masterUrl; site.Update(); site.MasterUrl = masterUrl; site.CustomMasterUrl = masterUrl; site.Update();
} }
} }
{% endhighlight %} ```

View File

@@ -22,7 +22,7 @@ As I read more, I realized this was a bigger clue than I initially thought. The
Here is my eventual solution. Unless they change the file location or configuration XML structure, its pretty safe, albeit a little hacky. I created a simple DynamicModulesHelper class. Here is my eventual solution. Unless they change the file location or configuration XML structure, its pretty safe, albeit a little hacky. I created a simple DynamicModulesHelper class.
{% highlight csharp %} ```csharp
public static class DynamicModuleHelper public static class DynamicModuleHelper
{ {
public const string DynamicModulesConfigRelativePath = public const string DynamicModulesConfigRelativePath =
@@ -93,12 +93,12 @@ public static class DynamicModuleHelper
return choicesNodes; return choicesNodes;
} }
} }
{% endhighlight %} ```
To get the Choices field options, you call the GetChoiceFieldOptions method, passing in the dynamic modules content type string (like this one: “Telerik.Sitefinity.DynamicTypes.Model.TestModule.TestModule”) and the name of the Choices field (like this: “RandomChoices”). So, my particular call for just a goofy test module I created was this: To get the Choices field options, you call the GetChoiceFieldOptions method, passing in the dynamic modules content type string (like this one: “Telerik.Sitefinity.DynamicTypes.Model.TestModule.TestModule”) and the name of the Choices field (like this: “RandomChoices”). So, my particular call for just a goofy test module I created was this:
{% highlight csharp %} ```csharp
KeyValuePair<string, string>[] choices = DynamicModuleHelper.GetChoiceFieldOptions( KeyValuePair<string, string>[] choices = DynamicModuleHelper.GetChoiceFieldOptions(
"Telerik.Sitefinity.DynamicTypes.Model.TestModule.TestModule", "Telerik.Sitefinity.DynamicTypes.Model.TestModule.TestModule",
"RandomChoices"); "RandomChoices");
{% endhighlight %} ```

View File

@@ -10,14 +10,14 @@ After you create and activate a dynamic module with Module Builder in Sitefinity
## ContentViewConfig.config ## ContentViewConfig.config
A config:link element is added under contentViewControls. Example: A config:link element is added under contentViewControls. Example:
{% highlight xml %} ```xml
<config:link definitionName="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChangeBackendDefinition" path="dynamicModulesConfig/contentViewControls/Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChangeBackendDefinition" module="ModuleBuilder" /> <config:link definitionName="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChangeBackendDefinition" path="dynamicModulesConfig/contentViewControls/Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChangeBackendDefinition" module="ModuleBuilder" />
{% endhighlight %} ```
## DynamicModulesConfig.config ## DynamicModulesConfig.config
And entire contentViewControl section is added under the contentViewControls element. Example: And entire contentViewControl section is added under the contentViewControls element. Example:
{% highlight xml %} ```xml
<contentViewControl contentType="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" managerType="Telerik.Sitefinity.DynamicModules.DynamicModuleManager, Telerik.Sitefinity" useWorkflow="True" definitionName="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChangeBackendDefinition"> <contentViewControl contentType="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" managerType="Telerik.Sitefinity.DynamicModules.DynamicModuleManager, Telerik.Sitefinity" useWorkflow="True" definitionName="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChangeBackendDefinition">
<views> <views>
<view gridCssClass="sfPagesTreeview" searchFields="Title" doNotBindOnClientWhenPageIsLoaded="False" allowPaging="True" allowUrlQueries="True" disableSorting="False" itemsPerPage="50" canUsersSetItemsPerPage="False" sortExpression="LastModified DESC" detailsPageId="00000000-0000-0000-0000-000000000000" webServiceBaseUrl="~/Sitefinity/Services/DynamicModules/Data.svc/" templateEvaluationMode="None" itemsParentId="00000000-0000-0000-0000-000000000000" renderLinksInMasterView="True" enableSocialSharing="False" displayMode="Read" useWorkflow="True" title="Config changes" viewType="Telerik.Sitefinity.DynamicModules.Web.UI.Backend.DynamicContentMasterGridView" viewName="Config changeBackendList" type:this="Telerik.Sitefinity.Web.UI.ContentUI.Views.Backend.Master.Config.MasterGridViewElement, Telerik.Sitefinity"> <view gridCssClass="sfPagesTreeview" searchFields="Title" doNotBindOnClientWhenPageIsLoaded="False" allowPaging="True" allowUrlQueries="True" disableSorting="False" itemsPerPage="50" canUsersSetItemsPerPage="False" sortExpression="LastModified DESC" detailsPageId="00000000-0000-0000-0000-000000000000" webServiceBaseUrl="~/Sitefinity/Services/DynamicModules/Data.svc/" templateEvaluationMode="None" itemsParentId="00000000-0000-0000-0000-000000000000" renderLinksInMasterView="True" enableSocialSharing="False" displayMode="Read" useWorkflow="True" title="Config changes" viewType="Telerik.Sitefinity.DynamicModules.Web.UI.Backend.DynamicContentMasterGridView" viewName="Config changeBackendList" type:this="Telerik.Sitefinity.Web.UI.ContentUI.Views.Backend.Master.Config.MasterGridViewElement, Telerik.Sitefinity">
@@ -205,11 +205,11 @@ And entire contentViewControl section is added under the contentViewControls ele
</view> </view>
</views> </views>
</contentViewControl> </contentViewControl>
{% endhighlight %} ```
## SecurityConfig.config ## SecurityConfig.config
A permission element is added underneath the permissions node. Example: A permission element is added underneath the permissions node. Example:
{% highlight xml %} ```xml
<permission title="Config changes permissions" description="Represents the most common application security permissions." loginUrl="~/Sitefinity/Login" ajaxLoginUrl="~/Sitefinity/Login/Ajax" name="Configchangetests-ConfigChange"> <permission title="Config changes permissions" description="Represents the most common application security permissions." loginUrl="~/Sitefinity/Login" ajaxLoginUrl="~/Sitefinity/Login/Ajax" name="Configchangetests-ConfigChange">
<actions> <actions>
<add title="View Config changes" description="Allows or denies viewing Config changes." type="View" name="View" /> <add title="View Config changes" description="Allows or denies viewing Config changes." type="View" name="View" />
@@ -219,19 +219,19 @@ A permission element is added underneath the permissions node. Example:
<add title="Change a Config changes permissions" description="Allows or denies changing the permissions of Config changes." type="ChangePermissions" name="ChangePermissions" /> <add title="Change a Config changes permissions" description="Allows or denies changing the permissions of Config changes." type="ChangePermissions" name="ChangePermissions" />
</actions> </actions>
</permission> </permission>
{% endhighlight %} ```
## ToolboxesConfig.config ## ToolboxesConfig.config
A tool is added in the tools section. Example: A tool is added in the tools section. Example:
{% highlight xml %} ```xml
<add enabled="True" type="Telerik.Sitefinity.DynamicModules.Web.UI.Frontend.DynamicContentView, Telerik.Sitefinity" title="Config changes" cssClass="sfNewsViewIcn" moduleName="Config change tests" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" DefaultMasterTemplateKey="844f4eff-9a33-4799-84e5-2973d7a3db9b" DefaultDetailTemplateKey="7fd83546-0785-4050-998f-06428e7c6fa1" visibilityMode="None" name="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" /> <add enabled="True" type="Telerik.Sitefinity.DynamicModules.Web.UI.Frontend.DynamicContentView, Telerik.Sitefinity" title="Config changes" cssClass="sfNewsViewIcn" moduleName="Config change tests" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" DefaultMasterTemplateKey="844f4eff-9a33-4799-84e5-2973d7a3db9b" DefaultDetailTemplateKey="7fd83546-0785-4050-998f-06428e7c6fa1" visibilityMode="None" name="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" />
{% endhighlight %} ```
## WorkflowConfig.config ## WorkflowConfig.config
A workflow type is added in the workflowTypes section. Example: A workflow type is added in the workflowTypes section. Example:
{% highlight xml %} ```xml
<add title="Config change" moduleName="Config change tests" contentType="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" /> <add title="Config change" moduleName="Config change tests" contentType="Telerik.Sitefinity.DynamicTypes.Model.Configchangetests.ConfigChange" />
{% endhighlight %} ```
## Deactivation ## Deactivation
No configuration changes are made in the Sitefinity configuration files when you just deactivate a dynamic module with Module Builder. No configuration changes are made in the Sitefinity configuration files when you just deactivate a dynamic module with Module Builder.

View File

@@ -12,20 +12,20 @@ You have to setup the error pages in two places in the applications web.confi
## system.web/customErrors ## system.web/customErrors
You have to setup your error pages in the system.web/customErrors section of your web.config to cover calls to non-existent *.aspx pages (and probably other ASP.NET-handled pages as well). My customErrors section looks like this. It will be expanded to cover other error codes. You have to setup your error pages in the system.web/customErrors section of your web.config to cover calls to non-existent *.aspx pages (and probably other ASP.NET-handled pages as well). My customErrors section looks like this. It will be expanded to cover other error codes.
{% highlight xml %} ```xml
<customErrors mode="On" redirectMode="ResponseRewrite"> <customErrors mode="On" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="~/Static/404.htm"/> <error statusCode="404" redirect="~/Static/404.htm"/>
</customErrors> </customErrors>
{% endhighlight %} ```
## system.webServer/httpErrors ## system.webServer/httpErrors
The next section you need is the system.webServer/httpErrors section. I never knew this section exists, but it corresponds to the Errors panel in IIS Manager 7.5 for your website. This section covers request for non-existing folders and static files (like /bogusFolder or /bogusFile.htm). Mine looks like this and it will likewise be expanded for other error codes. The next section you need is the system.webServer/httpErrors section. I never knew this section exists, but it corresponds to the Errors panel in IIS Manager 7.5 for your website. This section covers request for non-existing folders and static files (like /bogusFolder or /bogusFile.htm). Mine looks like this and it will likewise be expanded for other error codes.
{% highlight xml %} ```xml
<httpErrors errorMode="Custom" defaultResponseMode="File"> <httpErrors errorMode="Custom" defaultResponseMode="File">
<remove statusCode="404"/> <remove statusCode="404"/>
<error statusCode="404" path="Static\404.htm"/> <error statusCode="404" path="Static\404.htm"/>
</httpErrors> </httpErrors>
{% endhighlight %} ```
Because IIS has default settings for this stuff, you need to use the remove element before adding your own error messages. You can find more specifics on this configuration element here: [http://www.iis.net/configreference/system.webserver/httperrors](http://www.iis.net/configreference/system.webserver/httperrors). Because IIS has default settings for this stuff, you need to use the remove element before adding your own error messages. You can find more specifics on this configuration element here: [http://www.iis.net/configreference/system.webserver/httperrors](http://www.iis.net/configreference/system.webserver/httperrors).

View File

@@ -25,7 +25,7 @@ Turns out, I was right. With some more trial and error from that point on, I cam
Override ConcatenationTranslator Override ConcatenationTranslator
First of all, you need to create a new class that inherits from ConcatenationTranslator. This is a public class in the Telerik.Sitefinity.Publishing.Translators namespace. I called my class CustomConcatenationTranslator. IN the base class, the Translate method turns an array of object values into a space-separated string. Ill show the code in a minute, but the first thing you need to do after creating the class is register it with the pipeline. In Global.asax.cs, add these lines (around any other code you have there): First of all, you need to create a new class that inherits from ConcatenationTranslator. This is a public class in the Telerik.Sitefinity.Publishing.Translators namespace. I called my class CustomConcatenationTranslator. IN the base class, the Translate method turns an array of object values into a space-separated string. Ill show the code in a minute, but the first thing you need to do after creating the class is register it with the pipeline. In Global.asax.cs, add these lines (around any other code you have there):
{% highlight csharp %} ```csharp
protected void Application_Start(object sender, EventArgs e) protected void Application_Start(object sender, EventArgs e)
{ {
Bootstrapper.Initialized += Bootstrapper_Initialized; Bootstrapper.Initialized += Bootstrapper_Initialized;
@@ -38,13 +38,13 @@ private void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.Exe
PipeTranslatorFactory.RegisterTranslator(new CustomConcatenationTranslator()); PipeTranslatorFactory.RegisterTranslator(new CustomConcatenationTranslator());
} }
} }
{% endhighlight %} ```
You dont have to unregistered the existing ConcatenationTranslator. Your registration will replace it as long as you dont rename the translator by overriding its Name property. You dont have to unregistered the existing ConcatenationTranslator. Your registration will replace it as long as you dont rename the translator by overriding its Name property.
What I wanted to do was check if the data being translated was a TrackedList<Guid> type. This is what your taxonomy fields are in code. Here is my code for the CustomConcatenationTranslator class. What I wanted to do was check if the data being translated was a TrackedList<Guid> type. This is what your taxonomy fields are in code. Here is my code for the CustomConcatenationTranslator class.
{% highlight csharp %} ```csharp
public class CustomConcatenationTranslator : ConcatenationTranslator public class CustomConcatenationTranslator : ConcatenationTranslator
{ {
private readonly TaxonomyManager _taxonomyManager; private readonly TaxonomyManager _taxonomyManager;
@@ -105,7 +105,7 @@ public class CustomConcatenationTranslator : ConcatenationTranslator
return string.Join(" ", taxNames); return string.Join(" ", taxNames);
} }
} }
{% endhighlight %} ```
It should be pretty simple to follow. Basically, if I find a data value is a TrackedList<Guid>, I get the Taxon items with that Guid ID, get the name of that Taxon and then concatenate those values, separated by a space. If the data object is anything other than a TrackedList<Guid>, I used the default ConcatenationTranslator behavior. It should be pretty simple to follow. Basically, if I find a data value is a TrackedList<Guid>, I get the Taxon items with that Guid ID, get the name of that Taxon and then concatenate those values, separated by a space. If the data object is anything other than a TrackedList<Guid>, I used the default ConcatenationTranslator behavior.

View File

@@ -19,17 +19,17 @@ I am using a WidgetDesigner in which I have the PagesSelector control. My goal i
Everything works fine. Except, once I save a selection in the PagesSelector, on subsequent edits, the currently selected items would not show up, as described above. Everything works fine. Except, once I save a selection in the PagesSelector, on subsequent edits, the currently selected items would not show up, as described above.
Here is the bug I found in the Sitefinity code. The set_selectedItemIds function is really simple. It looks like this: Here is the bug I found in the Sitefinity code. The set_selectedItemIds function is really simple. It looks like this:
{% highlight javascript %} ```javascript %}
set_selectedItemIds: function(ids) { set_selectedItemIds: function(ids) {
this._selectedItemIds = ids; this._selectedItemIds = ids;
this._updateGridSelection(); this._updateGridSelection();
this._updateTreeSelection(); this._updateTreeSelection();
} }
{% endhighlight %} ```
It updates a property (_selectedItemIds) and then updates the grid (not sure what that is) and then the tree (of page nodes). The _updateTreeSelection method is what were looking forthis is where the bug is. The method looks like this: It updates a property (_selectedItemIds) and then updates the grid (not sure what that is) and then the tree (of page nodes). The _updateTreeSelection method is what were looking forthis is where the bug is. The method looks like this:
{% highlight javascript %} ```javascript %}
_updateTreeSelection: function () { _updateTreeSelection: function () {
if (this._treeIsBound == false) { if (this._treeIsBound == false) {
this._treeMustBeUpdated = true; this._treeMustBeUpdated = true;
@@ -53,13 +53,13 @@ _updateTreeSelection: function () {
} }
this._raiseSelectionApplied(this, {}); this._raiseSelectionApplied(this, {});
} }
{% endhighlight %} ```
The problem is on line 13. tree.get_selectedItems() returns an empty array when there are no items selected. So, the expression if (selectedItems) { } will always be truebut we want to get to the else statement, as you can see, to set the selection from the this._selectedItemIds array. The problem is on line 13. tree.get_selectedItems() returns an empty array when there are no items selected. So, the expression if (selectedItems) { } will always be truebut we want to get to the else statement, as you can see, to set the selection from the this._selectedItemIds array.
The beauty (and danger!) of javascript is that you can easily fix something like this in your own code by simply redefining their method. Here is my code that fixes this bug: The beauty (and danger!) of javascript is that you can easily fix something like this in your own code by simply redefining their method. Here is my code that fixes this bug:
{% highlight javascript %} ```javascript %}
var wrapper = this.get_pagesSelector(); var wrapper = this.get_pagesSelector();
var selector = this.get_pagesSelector().get_pageSelector(); var selector = this.get_pagesSelector().get_pageSelector();
var selecting = false; var selecting = false;
@@ -99,7 +99,7 @@ wrapper.add_selectionApplied(function () {
selector._updateTreeSelection = oldMethod; selector._updateTreeSelection = oldMethod;
} }
}); });
{% endhighlight %} ```
First, I attach to the selectionApplied method. If you try to do the above code before that is done, your selection will just be overridden (or just not worknot sure which). This event will get called when you call set_selectedItemIds. To avoid an infinite loop, then, I use the selecting flag at the top of the event function I am attaching. First, I attach to the selectionApplied method. If you try to do the above code before that is done, your selection will just be overridden (or just not worknot sure which). This event will get called when you call set_selectedItemIds. To avoid an infinite loop, then, I use the selecting flag at the top of the event function I am attaching.

View File

@@ -10,7 +10,7 @@ I had a case recently where I needed to convert a LINQ expression of the type of
First, the helper method in a static class. First, the helper method in a static class.
{% highlight csharp %} ```csharp
internal static Expression<Func<TConcrete, bool>> ConvertToConcreteExpression<TConcrete, TInterface>( Expression<Func<TInterface, bool>> interfaceExpression) internal static Expression<Func<TConcrete, bool>> ConvertToConcreteExpression<TConcrete, TInterface>( Expression<Func<TInterface, bool>> interfaceExpression)
{ {
if (!typeof(TInterface).IsAssignableFrom(typeof(TConcrete))) if (!typeof(TInterface).IsAssignableFrom(typeof(TConcrete)))
@@ -20,11 +20,11 @@ internal static Expression<Func<TConcrete, bool>> ConvertToConcreteExpression<TC
return TransformVisitor<TConcrete, TInterface>.Transform(interfaceExpression); return TransformVisitor<TConcrete, TInterface>.Transform(interfaceExpression);
} }
{% endhighlight %} ```
Here is the TransformVisitor class. Here is the TransformVisitor class.
{% highlight csharp %} ```csharp
internal class TransformVisitor<TConcrete, TInterface> : ExpressionVisitor internal class TransformVisitor<TConcrete, TInterface> : ExpressionVisitor
{ {
private readonly ParameterExpression _param = Expression.Parameter(typeof(TConcrete), "param_0"); private readonly ParameterExpression _param = Expression.Parameter(typeof(TConcrete), "param_0");
@@ -71,4 +71,4 @@ internal class TransformVisitor<TConcrete, TInterface> : ExpressionVisitor
return base.VisitParameter(node); return base.VisitParameter(node);
} }
} }
{% endhighlight %} ```

View File

@@ -16,7 +16,7 @@ DO include a trailing slash
Example: “folder1/folder2/otherfolder/” Example: “folder1/folder2/otherfolder/”
Given this code: Given this code:
{% highlight csharp %} ```csharp
FolderManager fm = new FolderManager(); FolderManager fm = new FolderManager();
FolderCriteria folderCrit = new FolderCriteria(); FolderCriteria folderCrit = new FolderCriteria();
folderCrit.AddFilter( folderCrit.AddFilter(
@@ -25,7 +25,7 @@ CriteriaFilterOperator.EqualTo,
folderPath); folderPath);
FolderData folder = fm.GetList(folderCrit).FirstOrDefault(); FolderData folder = fm.GetList(folderCrit).FirstOrDefault();
{% endhighlight %} ```
Then the “folderPath” variable needs to be in this format: “folderName1/folderName2/”. The same would apply for finding all the content in a folder via the contents path. Then the “folderPath” variable needs to be in this format: “folderName1/folderName2/”. The same would apply for finding all the content in a folder via the contents path.
@@ -37,9 +37,9 @@ Do NOT use a trailing slash
Example: “\taxonomy1\taxonomy2\othertaxonomy” Example: “\taxonomy1\taxonomy2\othertaxonomy”
So, given this code: So, given this code:
{% highlight csharp %} ```csharp
ITaxonomyManager _taxManager = ObjectFactory.GetTaxonomyManager(); ITaxonomyManager _taxManager = ObjectFactory.GetTaxonomyManager();
TaxonomyData tax = _taxManager.GetItem(taxPath); TaxonomyData tax = _taxManager.GetItem(taxPath);
{% endhighlight %} ```
The “taxPath” variable needs to be in this format: “\rootTaxonomyName\subTaxonomyName1\subTaxonomyName2″. The “taxPath” variable needs to be in this format: “\rootTaxonomyName\subTaxonomyName1\subTaxonomyName2″.

View File

@@ -20,23 +20,23 @@ Whatever the case may be, I started snooping around on the net for others having
I started snooping around with decompiling the Ektron.Cms.ObjectFactory DLL code where the ITaxonomyManager interface is defined. Everything looked goodit had the same-named methods, but was using the OperationContract attribute which lets you define the action name. The two GetList actions were defined with different names, so something wasnt matching up with the error I was seeing in my import project. You can see that the two GetList methods have different Action values, making it OK for WCF. I started snooping around with decompiling the Ektron.Cms.ObjectFactory DLL code where the ITaxonomyManager interface is defined. Everything looked goodit had the same-named methods, but was using the OperationContract attribute which lets you define the action name. The two GetList actions were defined with different names, so something wasnt matching up with the error I was seeing in my import project. You can see that the two GetList methods have different Action values, making it OK for WCF.
{% highlight csharp %} ```csharp
[OperationContract(Action="GetList")] [OperationContract(Action="GetList")]
List<TaxonomyData> GetList(TaxonomyCriteria criteria); List<TaxonomyData> GetList(TaxonomyCriteria criteria);
[OperationContract(Action="GetListByCustomProperty", Name="GetListByCustomPropertyCriteria")] [OperationContract(Action="GetListByCustomProperty", Name="GetListByCustomPropertyCriteria")]
List<TaxonomyData> GetList(TaxonomyCustomPropertyCriteria criteria); List<TaxonomyData> GetList(TaxonomyCustomPropertyCriteria criteria);
{% endhighlight %} ```
When I decompiled the Ektron.Cms.ObjectFactory DLL that I was using in my import project, I found the problem. You can see it here: When I decompiled the Ektron.Cms.ObjectFactory DLL that I was using in my import project, I found the problem. You can see it here:
{% highlight csharp %} ```csharp
[OperationContract(Action="GetList")] [OperationContract(Action="GetList")]
List<TaxonomyData> GetList(TaxonomyCriteria criteria); List<TaxonomyData> GetList(TaxonomyCriteria criteria);
[OperationContract(Action="GetList")] [OperationContract(Action="GetList")]
List<TaxonomyData> GetList(TaxonomyCustomPropertyCriteria criteria); List<TaxonomyData> GetList(TaxonomyCustomPropertyCriteria criteria);
{% endhighlight %} ```
Notice how the Action is defined with the same name. I checked the DLL versions of my DLL and the DLL in the Ektron 8.5 SP3 site I was pushing content too. They were both the same: 8.5.0.356. So, somewhere along the line, Ektron fixed the issue without updating the AssemblyFileVersion to signify a bug fix/updated code. Once I copied the DLL from the SP3 sites bin folder to my import project, it worked just fine. Notice how the Action is defined with the same name. I checked the DLL versions of my DLL and the DLL in the Ektron 8.5 SP3 site I was pushing content too. They were both the same: 8.5.0.356. So, somewhere along the line, Ektron fixed the issue without updating the AssemblyFileVersion to signify a bug fix/updated code. Once I copied the DLL from the SP3 sites bin folder to my import project, it worked just fine.

View File

@@ -15,7 +15,7 @@ So, lesson #1 when getting 401 in SharePoint: debug your application.
Lesson #2: apparently accessing the DefaultPage property of a PublishingWeb requires elevated privileges. Here was my code: Lesson #2: apparently accessing the DefaultPage property of a PublishingWeb requires elevated privileges. Here was my code:
{% highlight csharp %} ```csharp
private string GetDefaultPageUrl() private string GetDefaultPageUrl()
{ {
if (!PublishingWeb.IsPublishingWeb(SPContext.Current.Web)) if (!PublishingWeb.IsPublishingWeb(SPContext.Current.Web))
@@ -31,11 +31,11 @@ private string GetDefaultPageUrl()
return web.DefaultPage == null ? string.Empty : web.DefaultPage.Url; return web.DefaultPage == null ? string.Empty : web.DefaultPage.Url;
} }
{% endhighlight %} ```
That last line was throwing the 401. So, the solution was to wrap it in an SPSecurity.RunWithElevatedPrivileges call, like this: That last line was throwing the 401. So, the solution was to wrap it in an SPSecurity.RunWithElevatedPrivileges call, like this:
{% highlight csharp %} ```csharp
private string GetDefaultPageUrl() private string GetDefaultPageUrl()
{ {
string url = string.Empty; string url = string.Empty;
@@ -65,7 +65,7 @@ private string GetDefaultPageUrl()
}); });
return url; return url;
} }
{% endhighlight %} ```
Thanks to this post for the answer about re-opening the site and web inside the RunWithElevatedPrivileges code: Thanks to this post for the answer about re-opening the site and web inside the RunWithElevatedPrivileges code:
[http://henry-chong.com/2010/11/sharepoint-anonymous-access-and-publishing-web-default-page](http://henry-chong.com/2010/11/sharepoint-anonymous-access-and-publishing-web-default-page). [http://henry-chong.com/2010/11/sharepoint-anonymous-access-and-publishing-web-default-page](http://henry-chong.com/2010/11/sharepoint-anonymous-access-and-publishing-web-default-page).

View File

@@ -25,18 +25,18 @@ Still, the post mentioned above got me on the right track. By commenting out co
I had the following code in my HttpModule. Here is what Init method looked like: I had the following code in my HttpModule. Here is what Init method looked like:
{% highlight csharp %} ```csharp
public void Init(HttpApplication context) public void Init(HttpApplication context)
{ {
context.BeginRequest += SetupOutputFilter; context.BeginRequest += SetupOutputFilter;
context.PreSendRequestHeaders += WritePdfHeaders; context.PreSendRequestHeaders += WritePdfHeaders;
context.PreSendRequestContent += WritePdfToOutput; context.PreSendRequestContent += WritePdfToOutput;
} }
{% endhighlight %} ```
Commenting out the tie into the BeginRequest event fixed the issue, so it had to be something there. SetupOutputFilter looked like this: Commenting out the tie into the BeginRequest event fixed the issue, so it had to be something there. SetupOutputFilter looked like this:
{% highlight csharp %} ```csharp
private void SetupOutputFilter(object sender, EventArgs e) private void SetupOutputFilter(object sender, EventArgs e)
{ {
if (!IsPdfRequest) if (!IsPdfRequest)
@@ -48,11 +48,11 @@ private void SetupOutputFilter(object sender, EventArgs e)
_pdfStream = new PdfMemoryStream(response.Filter); _pdfStream = new PdfMemoryStream(response.Filter);
response.Filter = _pdfStream; response.Filter = _pdfStream;
} }
{% endhighlight %} ```
Commenting out the if expression also fixed the issue. My IsPdfRequest property looked like this: Commenting out the if expression also fixed the issue. My IsPdfRequest property looked like this:
{% highlight csharp %} ```csharp
private static bool IsPdfRequest private static bool IsPdfRequest
{ {
get get
@@ -61,7 +61,7 @@ private static bool IsPdfRequest
&& HttpContext.Current.Request["as"] == "pdf"; && HttpContext.Current.Request["as"] == "pdf";
} }
} }
{% endhighlight %} ```
And there you have my access to the HttpContext object. I kind of needed this though, so I thought it might be a timing issue. Maybe accessing this on BeginRequest was the problem. I took a look at the ordering of the HttpModule events to find a good replacement. This StackOverflow thread helped me there: And there you have my access to the HttpContext object. I kind of needed this though, so I thought it might be a timing issue. Maybe accessing this on BeginRequest was the problem. I took a look at the ordering of the HttpModule events to find a good replacement. This StackOverflow thread helped me there:

View File

@@ -8,10 +8,10 @@ tags: [sharepoint]
--- ---
I ran across an issue today in SharePoint 2010 where the Page Layout button would not open. It would throw the following error in Internet Explorer: I ran across an issue today in SharePoint 2010 where the Page Layout button would not open. It would throw the following error in Internet Explorer:
{% highlight javascript %} ```javascript %}
SCRIPT5007: Unable to get property nodeName of undefined or null reference SCRIPT5007: Unable to get property nodeName of undefined or null reference
cui.js, line 2 character 6422 cui.js, line 2 character 6422
{% endhighlight %} ```
The following link gave me the answer. The following link gave me the answer.

View File

@@ -9,6 +9,6 @@ tags: []
Here it is, folks: some of the dumbest code Ive ever written and I just now noticed it. Here it is, folks: some of the dumbest code Ive ever written and I just now noticed it.
{% highlight csharp %} ```csharp
string.Concat("attachment; filename=\"", string.Concat(pagePdf.Name, ".pdf"), "\""); string.Concat("attachment; filename=\"", string.Concat(pagePdf.Name, ".pdf"), "\"");
{% endhighlight %} ```

View File

@@ -11,7 +11,7 @@ I ran into the following error while working with an installation of EPiServer 7
First, heres the error and stack trace: First, heres the error and stack trace:
{% highlight text %} ```text
2014-03-27 12:12:43,396 [6] ERROR EPiServer.Global: 1.2.5 Unhandled exception in ASP.NET 2014-03-27 12:12:43,396 [6] ERROR EPiServer.Global: 1.2.5 Unhandled exception in ASP.NET
System.Web.HttpException (0x80004005): The file /link/cc299342a697494c8a4bc47717210bf0.aspx does not exist. System.Web.HttpException (0x80004005): The file /link/cc299342a697494c8a4bc47717210bf0.aspx does not exist.
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
@@ -22,11 +22,11 @@ at System.Web.Routing.PageRouteHandler.GetHttpHandler(RequestContext requestCont
at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
{% endhighlight %} ```
As it turns out, I did not have a TemplateDescriptor attribute on the page template that I was trying to access. Adding the following TemplateDescriptor attribute to the code-behind class for my page template saved me. As it turns out, I did not have a TemplateDescriptor attribute on the page template that I was trying to access. Adding the following TemplateDescriptor attribute to the code-behind class for my page template saved me.
{% highlight csharp %} ```csharp
[TemplateDescriptor(Path = "~/Templates/PageTemplates/Home.aspx")] [TemplateDescriptor(Path = "~/Templates/PageTemplates/Home.aspx")]
public partial class Home : TemplatePage<HomePage> public partial class Home : TemplatePage<HomePage>
{% endhighlight %} ```

View File

@@ -10,7 +10,7 @@ tags: [episerver]
## Problem ## Problem
Ive been dealing with an issue in EPiServer 7 recently. I got this error when trying to log into the admin back-end of the site. Ive been dealing with an issue in EPiServer 7 recently. I got this error when trying to log into the admin back-end of the site.
{% highlight text %} ```text
Cannot decrypt password Cannot decrypt password
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
@@ -28,7 +28,7 @@ EPiServer.Common.Security.HMACPasswordProvider.DecryptPassword(Byte[] ciphertext
EPiServer.Common.Web.Authorization.Integrator.SynchronizeUser(MembershipUser membershipUser, String password, Boolean enableCreateNew) +1116 EPiServer.Common.Web.Authorization.Integrator.SynchronizeUser(MembershipUser membershipUser, String password, Boolean enableCreateNew) +1116
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80 System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165
{% endhighlight %} ```
## Scenario ## Scenario
We originally installed the Relate+ site for our EPiServer installation. Through various bad decisions, we didnt keep the custom code and templates we wrote separate from the Relate+ stuff. So, we inevitably created a mess where we did not need a ton of the Relate+ templates, page types, block types, etc but we could not longer easily pull our custom stuff out from the tangled mess. We originally installed the Relate+ site for our EPiServer installation. Through various bad decisions, we didnt keep the custom code and templates we wrote separate from the Relate+ stuff. So, we inevitably created a mess where we did not need a ton of the Relate+ templates, page types, block types, etc but we could not longer easily pull our custom stuff out from the tangled mess.

View File

@@ -45,15 +45,15 @@ Using Sitefinity Thunder, create your widget. Don't create the designer at this
##### Step 1.1: Update controller properties ##### Step 1.1: Update controller properties
Remove whatever properties Thunder automatically adds on the MVC controller and add your own List property of type Guid. Remove whatever properties Thunder automatically adds on the MVC controller and add your own List property of type Guid.
{% highlight csharp %} ```csharp
[Category("Widget Properties")] [Category("Widget Properties")]
public Guid List { get; set; } public Guid List { get; set; }
{% endhighlight %} ```
##### Step 1.2: Update widget view model ##### Step 1.2: Update widget view model
I added a simple POCO to describe each FAQ item (containing a question and answer) and then added a list of these POCOs as the only property on my view model. I added a simple POCO to describe each FAQ item (containing a question and answer) and then added a list of these POCOs as the only property on my view model.
{% highlight csharp %} ```csharp
public class FAQListModel public class FAQListModel
{ {
public List<FAQItem> Items { get; set; } public List<FAQItem> Items { get; set; }
@@ -64,12 +64,12 @@ public class FAQItem
public string Answer { get; set; } public string Answer { get; set; }
public string Question { get; set; } public string Question { get; set; }
} }
{% endhighlight %} ```
##### Step 1.3: Update Index action ##### Step 1.3: Update Index action
Update the Index action to use the List property to access the content-author-chosen list, pull the items and stick them in the model. Update the Index action to use the List property to access the content-author-chosen list, pull the items and stick them in the model.
{% highlight csharp %} ```csharp
public ActionResult Index() public ActionResult Index()
{ {
var model = new FAQListModel(); var model = new FAQListModel();
@@ -91,7 +91,7 @@ public ActionResult Index()
return View("Default", model); return View("Default", model);
} }
{% endhighlight %} ```
#### Step 2: Create widget designer/public #### Step 2: Create widget designer/public
Once your widget is created, you can create your widget designer. Using Thunder, create a widget designer for an existing widget. Name your widget designer. I use the name of the widget and append "Designer". Once your widget is created, you can create your widget designer. Using Thunder, create a widget designer for an existing widget. Name your widget designer. I use the name of the widget and append "Designer".

View File

@@ -11,10 +11,10 @@ tags: [sitefinity]
When you use Sitefinity Thunder (a great help, by the way) to generate a Widget Designer for an existing widget that has a boolean property, you get this javascript in the auto-generated javascript file (lets say my boolean field is named HasSubMenu): When you use Sitefinity Thunder (a great help, by the way) to generate a Widget Designer for an existing widget that has a boolean property, you get this javascript in the auto-generated javascript file (lets say my boolean field is named HasSubMenu):
{% highlight javascript %} ```javascript %}
/* RefreshUI HasSubMenu */ /* RefreshUI HasSubMenu */
jQuery(this.get_hasSubMenu()).attr("checked", controlData.HasSubMenu); jQuery(this.get_hasSubMenu()).attr("checked", controlData.HasSubMenu);
{% endhighlight %} ```
This code is in the refreshUI method. Its supposed to mark a checkbox as checked if HasSubMenu is true and not check it if its false. The problem is, for some reason, HasSubMenu is a string in Javascript instead of a real boolean. So, HasSubMenu will be either “true” or “false”both of which are true values in Javascript. That is, because “true” and “false” are both non-empty strings, they evaluate to true when used as an expression. This code is in the refreshUI method. Its supposed to mark a checkbox as checked if HasSubMenu is true and not check it if its false. The problem is, for some reason, HasSubMenu is a string in Javascript instead of a real boolean. So, HasSubMenu will be either “true” or “false”both of which are true values in Javascript. That is, because “true” and “false” are both non-empty strings, they evaluate to true when used as an expression.
@@ -24,9 +24,9 @@ This means, no matter what you do with the checkbox, the next time you click “
The solution is pretty simple. Instead of using controlData.HasSubMenu for the expression by itself, update your Javascript so that you check if the string is “true” or not: controlData.HasSubMenu === "true". The line in the refreshUI method should now look like this: The solution is pretty simple. Instead of using controlData.HasSubMenu for the expression by itself, update your Javascript so that you check if the string is “true” or not: controlData.HasSubMenu === "true". The line in the refreshUI method should now look like this:
{% highlight javascript %} ```javascript %}
/* RefreshUI HasSubMenu */ /* RefreshUI HasSubMenu */
jQuery(this.get_hasSubMenu()).attr("checked", controlData.HasSubMenu === "true"); jQuery(this.get_hasSubMenu()).attr("checked", controlData.HasSubMenu === "true");
{% endhighlight %} ```
Now your checkbox will keep its value as you would expect. Now your checkbox will keep its value as you would expect.

View File

@@ -11,20 +11,20 @@ I noticed a goofy issue today while working with a jQuery countdown plugin. Thi
I was setting the date like this: I was setting the date like this:
{% highlight javascript %} ```javascript %}
element.countdown({ element.countdown({
until: new Date(10/13/14 00:00:00) until: new Date(10/13/14 00:00:00)
}); });
{% endhighlight %} ```
In Chrome, this worked just fine. The string “10/13/14 00:00:00″ parsed to a Date object for midnight on October 13th, 2014. In Chrome, this worked just fine. The string “10/13/14 00:00:00″ parsed to a Date object for midnight on October 13th, 2014.
In IE, however (versions10, 9 and 8 at least) it parsed as October 13th, 1914. Why? Who knows. Updating my string to “10/13/2014 00:00:00″ fixed it. My final javascript looked like this: In IE, however (versions10, 9 and 8 at least) it parsed as October 13th, 1914. Why? Who knows. Updating my string to “10/13/2014 00:00:00″ fixed it. My final javascript looked like this:
{% highlight javascript %} ```javascript %}
element.countdown({ element.countdown({
until: new Date(10/13/2014 00:00:00) until: new Date(10/13/2014 00:00:00)
}); });
{% endhighlight %} ```
So, be aware of this oddity! It caused my whole countdown widget to screw up because the current time was already past the “until” date.# So, be aware of this oddity! It caused my whole countdown widget to screw up because the current time was already past the “until” date.#

View File

@@ -22,7 +22,7 @@ class to use as your membership provider. Putting an `[Authorize]` attribute on
Here's my relevant web.config setup: Here's my relevant web.config setup:
{% highlight xml %} ```xml
<connectionStrings> <connectionStrings>
<add name="ADConnectionString" connectionString="<ldap connection string here>" /> <add name="ADConnectionString" connectionString="<ldap connection string here>" />
</connectionStrings> </connectionStrings>
@@ -39,15 +39,15 @@ Here's my relevant web.config setup:
attributeMapUsername="sAMAccountName"/> attributeMapUsername="sAMAccountName"/>
</providers> </providers>
</membership> </membership>
{% endhighlight %} ```
The tough part came when I wanted to limit access to users in that AD group. Microsoft doesn't provide a RoleProvider along with its ActiveDirectoryMembershipProvider. So, what to do? The tough part came when I wanted to limit access to users in that AD group. Microsoft doesn't provide a RoleProvider along with its ActiveDirectoryMembershipProvider. So, what to do?
I tried several methods I found online. Most of them were based on creating my own custom RoleProvider and querying AD to iterate through the user's groups (treating them like roles) and seeing if one of them matched my AD group I was looking for. However, I could never get it to work. Each code example I found eventually gave me this AD error when I iterated through the current user's AD groups: I tried several methods I found online. Most of them were based on creating my own custom RoleProvider and querying AD to iterate through the user's groups (treating them like roles) and seeing if one of them matched my AD group I was looking for. However, I could never get it to work. Each code example I found eventually gave me this AD error when I iterated through the current user's AD groups:
{% highlight text %} ```text
The specified directory service attribute or value does not exist. The specified directory service attribute or value does not exist.
{% endhighlight %} ```
## The Solution ## The Solution
@@ -55,7 +55,7 @@ Eventually, I found a solution online that worked. Instead of setting up a custo
Here is my custom AuthorizeAttribute: Here is my custom AuthorizeAttribute:
{% highlight c# %} ```csharp %}
public class AuthorizeADAttribute : AuthorizeAttribute public class AuthorizeADAttribute : AuthorizeAttribute
{ {
private bool _authenticated; private bool _authenticated;
@@ -105,13 +105,13 @@ public class AuthorizeADAttribute : AuthorizeAttribute
return _authorized; return _authorized;
} }
} }
{% endhighlight %} ```
Notice that I also included a little code to distinguish between the user not being authenticated (which the call to base.AuthorizeCore takes care of) and not being authorized. Without the code in HandleUnauthorizedRequest, if the user successfully logs in but is not in the AD group, he just sees the log in screen again which doesn't communicate the problem very well. Notice that I also included a little code to distinguish between the user not being authenticated (which the call to base.AuthorizeCore takes care of) and not being authorized. Without the code in HandleUnauthorizedRequest, if the user successfully logs in but is not in the AD group, he just sees the log in screen again which doesn't communicate the problem very well.
The this.Log() code uses a Nuget package called this.Log. The LDAPHelper class is something I wrote. The code is below: The this.Log() code uses a Nuget package called this.Log. The LDAPHelper class is something I wrote. The code is below:
{% highlight c# %} ```csharp %}
public static class LDAPHelper public static class LDAPHelper
{ {
public static string GetLDAPContainer() public static string GetLDAPContainer()
@@ -171,18 +171,18 @@ public static class LDAPHelper
return new PrincipalContext(ContextType.Domain, null, container); return new PrincipalContext(ContextType.Domain, null, container);
} }
} }
{% endhighlight %} ```
My code is mostly based on example code I found on a very helpful [StackOverflow post][so-post]. My code is mostly based on example code I found on a very helpful [StackOverflow post][so-post].
To use this code, all you have to do is use your custom AuthorizeAttribute instead of the built-in one. Something like this: To use this code, all you have to do is use your custom AuthorizeAttribute instead of the built-in one. Something like this:
{% highlight c# %} ```csharp %}
[AuthorizeAD(Groups="Some AD group name")] [AuthorizeAD(Groups="Some AD group name")]
public class HomeController : Controller public class HomeController : Controller
{ {
} }
{% endhighlight %} ```
[so-post]: http://stackoverflow.com/questions/4342271/asp-net-mvc-forms-authorization-with-active-directory-groups/4383502#4383502 [so-post]: http://stackoverflow.com/questions/4342271/asp-net-mvc-forms-authorization-with-active-directory-groups/4383502#4383502

View File

@@ -13,13 +13,13 @@ the RabbitMQ Windows service and the logs still showed that the configuration fi
If you're experiencing the same problem, you'll see a similar error message in the RabbitMQ log file after If you're experiencing the same problem, you'll see a similar error message in the RabbitMQ log file after
you restart the Windows service. you restart the Windows service.
{% highlight text %} ```text
=INFO REPORT==== <date here> =INFO REPORT==== <date here>
node : rabbit@<server> node : rabbit@<server>
home dir : C:\Windows home dir : C:\Windows
config file(s) : c:/path/to/config/rabbitmq.config (not found) config file(s) : c:/path/to/config/rabbitmq.config (not found)
...some other stuff... ...some other stuff...
{% endhighlight %} ```
This will happen if you just install your RabbitMQ server with the normal, default installation process This will happen if you just install your RabbitMQ server with the normal, default installation process
and then try to add a configuration file later. By default, RabbitMQ doesn't install configuration file and just and then try to add a configuration file later. By default, RabbitMQ doesn't install configuration file and just
@@ -33,11 +33,11 @@ or removing a configuration file."
Oops. Guess I should have read the documentation more closely the first time around! The easiest way to Oops. Guess I should have read the documentation more closely the first time around! The easiest way to
do this is as follows (start a command prompt as administrator): do this is as follows (start a command prompt as administrator):
{% highlight text %} ```text
> cd "C:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.6.0\sbin" > cd "C:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.6.0\sbin"
> .\rabbitmq-service.bat remove > .\rabbitmq-service.bat remove
> .\rabbitmq-service.bat install > .\rabbitmq-service.bat install
> .\rabbitmq-service.bat start > .\rabbitmq-service.bat start
{% endhighlight %} ```
Of course, The path you cd into will depend on the version of RabbitMQ you have installed. Of course, The path you cd into will depend on the version of RabbitMQ you have installed.

View File

@@ -23,7 +23,7 @@ implemented `IHandleMessages<IEvent>` should be all I should have needed!
I was testing this with only partial success and so I thought it was working. I was testing this with only partial success and so I thought it was working.
{% highlight csharp %} ```csharp
public class EventHandler : IHandleMessages<IEvent> public class EventHandler : IHandleMessages<IEvent>
{ {
public void Handle(IEvent message) public void Handle(IEvent message)
@@ -31,7 +31,7 @@ public class EventHandler : IHandleMessages<IEvent>
... ...
} }
} }
{% endhighlight %} ```
## My Partial Success ## My Partial Success
The reason I had partial success was because I was also *explicitly* handling The reason I had partial success was because I was also *explicitly* handling
@@ -63,16 +63,16 @@ system produces.
So, I simply created a marker interface called `ICustomEvent`. So, I simply created a marker interface called `ICustomEvent`.
{% highlight csharp %} ```csharp
public interface ICustomEvent : IEvent { } public interface ICustomEvent : IEvent { }
{% endhighlight %} ```
Then, on all of my bus event classes, instead of implementing `IEvent` directly, Then, on all of my bus event classes, instead of implementing `IEvent` directly,
I implemented `ICustomEvent`. I implemented `ICustomEvent`.
My handler then looked like this. My handler then looked like this.
{% highlight csharp %} ```csharp
public class EventHandler : IHandleMessages<ICustomEvent> public class EventHandler : IHandleMessages<ICustomEvent>
{ {
public void Handle(ICustomEvent message) public void Handle(ICustomEvent message)
@@ -80,7 +80,7 @@ public class EventHandler : IHandleMessages<ICustomEvent>
... ...
} }
} }
{% endhighlight %} ```
Now, the right subscriptions are all set up and my single handler gets Now, the right subscriptions are all set up and my single handler gets
every single event published by my entire bus. every single event published by my entire bus.

View File

@@ -18,9 +18,9 @@ far behind!
So, I updated my NuGet package to the latest version of GitVersionTask. That's So, I updated my NuGet package to the latest version of GitVersionTask. That's
3.4.1 right now. Too bad, so sad! That caused this error: 3.4.1 right now. Too bad, so sad! That caused this error:
{% highlight xml %} ```xml
The "CreatePackages" task was not given a value for the required parameter "Version". 1 The "CreatePackages" task was not given a value for the required parameter "Version". 1
{% endhighlight %} ```
## The Problem ## The Problem
The problem turns out that NuGetPackager 0.5.5 is looking for a MSBuild property The problem turns out that NuGetPackager 0.5.5 is looking for a MSBuild property
@@ -37,19 +37,19 @@ CreatePackage task is called in NuGetPackager.
Open up your .csproj file directly in some text editor like Notepad++. Find Open up your .csproj file directly in some text editor like Notepad++. Find
these two lines at the bottom of the file: these two lines at the bottom of the file:
{% highlight xml %} ```xml
<Import Project="..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets" <Import Project="..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets"
Condition="Exists('..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets')" /> Condition="Exists('..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets')" />
<Import Project="..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets" <Import Project="..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets"
Condition="Exists('..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets')" /> Condition="Exists('..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets')" />
{% endhighlight %} ```
Before those two lines, add a target and a property group. The target will Before those two lines, add a target and a property group. The target will
create a task that translates the new property to the new property. The create a task that translates the new property to the new property. The
property group wil define a BuildDependsOn to call that target before the property group wil define a BuildDependsOn to call that target before the
CreatePackages target is called. CreatePackages target is called.
{% highlight xml %} ```xml
<Target Name="TranslateNugetVersion" <Target Name="TranslateNugetVersion"
Condition="'$(Configuration)' == 'Release'"> Condition="'$(Configuration)' == 'Release'">
<CreateProperty <CreateProperty
@@ -69,6 +69,6 @@ CreatePackages target is called.
Condition="Exists('..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets')" /> Condition="Exists('..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets')" />
<Import Project="..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets" <Import Project="..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets"
Condition="Exists('..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets')" /> Condition="Exists('..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets')" />
{% endhighlight %} ```
Now, when you build your project, everything should work great! Now, when you build your project, everything should work great!

View File

@@ -47,7 +47,7 @@ use to encrypt a `ClaimsIdentity` into a valid bearer token.
Update your server creation code like this: Update your server creation code like this:
{% highlight csharp %} ```csharp
var dataProtector; var dataProtector;
var server = TestServer.Create(app => var server = TestServer.Create(app =>
{ {
@@ -58,7 +58,7 @@ Update your server creation code like this:
typeof(OAuthBearerAuthenticationMiddleware).Namespace, typeof(OAuthBearerAuthenticationMiddleware).Namespace,
"Access_Token", "v1"); "Access_Token", "v1");
}); });
{% endhighlight %} ```
You have to get the `dataProtector` this way because it's the same way that You have to get the `dataProtector` this way because it's the same way that
the OWIN OAuth libraries get it before trying to decrypt the bearer token. the OWIN OAuth libraries get it before trying to decrypt the bearer token.
@@ -69,7 +69,7 @@ Once you've "captured" the `dataProtector`, in your integration test (or in some
helper code, probably) you can generate your `ClaimsIdentity` and then your helper code, probably) you can generate your `ClaimsIdentity` and then your
bearer token with the `dataProtector`. bearer token with the `dataProtector`.
{% highlight csharp %} ```csharp
// inside an integration test // inside an integration test
using (server) using (server)
{ {
@@ -89,4 +89,4 @@ bearer token with the `dataProtector`.
.GetAsync() .GetAsync()
.Result; .Result;
} }
{% endhighlight %} ```

View File

@@ -18,7 +18,7 @@ Here's what the problem looked like.
### The Error Message ### The Error Message
First things first, this is what the symptom looked like: First things first, this is what the symptom looked like:
{% highlight text %} ```text
[ComponentNotFoundException: No component for supporting the service System.Threading.Tasks.Task was found] [ComponentNotFoundException: No component for supporting the service System.Threading.Tasks.Task was found]
Castle.MicroKernel.DefaultKernel.Castle.MicroKernel.IKernelInternal.Resolve(Type service, IDictionary arguments, IReleasePolicy policy) +120 Castle.MicroKernel.DefaultKernel.Castle.MicroKernel.IKernelInternal.Resolve(Type service, IDictionary arguments, IReleasePolicy policy) +120
Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Resolve(IInvocation invocation) +147 Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Resolve(IInvocation invocation) +147
@@ -27,7 +27,7 @@ First things first, this is what the symptom looked like:
Castle.Proxies.Func`2Proxy.Invoke(OAuthMatchEndpointContext arg) +168 Castle.Proxies.Func`2Proxy.Invoke(OAuthMatchEndpointContext arg) +168
... ...
{% endhighlight %} ```
This is actually a pretty standard error when you're using Castle.Windsor. It usually This is actually a pretty standard error when you're using Castle.Windsor. It usually
means Windsor tried to resolve some dependency but discovered that it was missing a means Windsor tried to resolve some dependency but discovered that it was missing a
@@ -46,7 +46,7 @@ was that it had nothing to do with any TypedFactoryFacility.
So, I inspected my registrations a little closer. I basically had a setup like this. So, I inspected my registrations a little closer. I basically had a setup like this.
{% highlight csharp %} ```csharp
public class ChildClass : ParentClass public class ChildClass : ParentClass
{ {
public override Task DoSomething(Options options) public override Task DoSomething(Options options)
@@ -70,7 +70,7 @@ public class ParentClass : IInterface
return OnDoSomethingElse.Invoke(options); return OnDoSomethingElse.Invoke(options);
} }
} }
{% endhighlight %} ```
Notice a couple of things. Notice a couple of things.
1. ParentClass has several virtual methods. I'm only overriding one. 1. ParentClass has several virtual methods. I'm only overriding one.
@@ -114,13 +114,13 @@ Now, I hate property injection, so I was fine with just turning it off completel
the documentation link above also included instructions how to do it. I've included that code the documentation link above also included instructions how to do it. I've included that code
here. here.
{% highlight csharp %} ```csharp
var propInjector = Kernel.ComponentModelBuilder var propInjector = Kernel.ComponentModelBuilder
.Contributors .Contributors
.OfType<PropertiesDependenciesModelInspector>() .OfType<PropertiesDependenciesModelInspector>()
.Single(); .Single();
Kernel.ComponentModelBuilder.RemoveContributor(propInjector); Kernel.ComponentModelBuilder.RemoveContributor(propInjector);
{% endhighlight %} ```
I added this code into my Windsor container setup and tried again. Everything worked just I added this code into my Windsor container setup and tried again. Everything worked just
as expected. as expected.

View File

@@ -30,7 +30,7 @@ an `IEnumerable` in C# like an array or a `List<T>`.
The iterators are implemented as extension methods on the `ICatalogSystem` interface. So, iterating through all The iterators are implemented as extension methods on the `ICatalogSystem` interface. So, iterating through all
of the catalog entry MetaObjects looks like this. of the catalog entry MetaObjects looks like this.
{% highlight csharp %} ```csharp
using Mediachase.Commerce.Catalog; using Mediachase.Commerce.Catalog;
using Mediachase.MetaDataPlus; using Mediachase.MetaDataPlus;
@@ -42,7 +42,7 @@ foreach ((MetaObject metaObject, MetaDataContext metaDataContext) entryMO in cat
entryMO.metaObject["SomeCustomMetaFieldName"] = "external data source value here"; entryMO.metaObject["SomeCustomMetaFieldName"] = "external data source value here";
entryMO.metaObject.AcceptChanges(entryMO.metaDataContext); entryMO.metaObject.AcceptChanges(entryMO.metaDataContext);
} }
{% endhighlight %} ```
I implemented the separate iterators for NodeContent MetaObjects and the EntryContent I implemented the separate iterators for NodeContent MetaObjects and the EntryContent
MetaObjects. You easily use them in combination to iterate through the MetaObjects of the entire catalog tree. MetaObjects. You easily use them in combination to iterate through the MetaObjects of the entire catalog tree.
@@ -58,7 +58,7 @@ The extension method code for AllCatalogSystemEntryMetaObjects is pretty simple.
1. All entries 1. All entries
1. All meta objects 1. All meta objects
{% highlight csharp %} ```csharp
public static IEnumerable<(MetaObject metaObject, MetaDataContext metaDataContext)> AllCatalogSystemEntryMetaObjects( public static IEnumerable<(MetaObject metaObject, MetaDataContext metaDataContext)> AllCatalogSystemEntryMetaObjects(
this ICatalogSystem catalogSystem, this ICatalogSystem catalogSystem,
MetaDataContext metaDataContext) MetaDataContext metaDataContext)
@@ -77,7 +77,7 @@ public static IEnumerable<(MetaObject metaObject, MetaDataContext metaDataContex
} }
} }
} }
{% endhighlight %} ```
I broke the iteration down into separate iterators in this fashion so that I could easily iterate through all the entries (for example) in a single node, if I knew from the beginning which node I wanted to start at. If that was the case, I could easily write another extension method that took a node ID (or node code) as a parameter, use the ICatalogSystem to find that node and then pass the node ID to the CatalogSystemEntries iterator to iterate just the entries under that node. I broke the iteration down into separate iterators in this fashion so that I could easily iterate through all the entries (for example) in a single node, if I knew from the beginning which node I wanted to start at. If that was the case, I could easily write another extension method that took a node ID (or node code) as a parameter, use the ICatalogSystem to find that node and then pass the node ID to the CatalogSystemEntries iterator to iterate just the entries under that node.
@@ -93,7 +93,7 @@ The code is pretty simple. We implement an IEnumerable which uses our implement
The IEnumerator simply gets all the catalogs from the ICatalogSystem and, as you call MoveNext() (usually done for you by the foreach loop), increments an index value to give you the current CatalogDto.CatalogRow to work with. The IEnumerator simply gets all the catalogs from the ICatalogSystem and, as you call MoveNext() (usually done for you by the foreach loop), increments an index value to give you the current CatalogDto.CatalogRow to work with.
{% highlight csharp %} ```csharp
public class CatalogSystemCatalogs : IEnumerable<CatalogDto.CatalogRow> public class CatalogSystemCatalogs : IEnumerable<CatalogDto.CatalogRow>
{ {
private readonly CatalogSystemCatalogEnumerator _enumerator; private readonly CatalogSystemCatalogEnumerator _enumerator;
@@ -159,7 +159,7 @@ public class CatalogSystemCatalogEnumerator : IEnumerator<CatalogDto.CatalogRow>
private Lst<CatalogDto.CatalogRow> GetCatalogs() private Lst<CatalogDto.CatalogRow> GetCatalogs()
=> _catalogSystem.GetCatalogDto().Catalog.Freeze(); => _catalogSystem.GetCatalogDto().Catalog.Freeze();
} }
{% endhighlight %} ```
### CatalogSystemNodes Iterator ### CatalogSystemNodes Iterator
For the nodes iterator, things get a little more complicated. Nodes can be nested, so we have tree structure we have to navigate. We use a Queue to walk through the nodes in a breadth-first fashion. For the nodes iterator, things get a little more complicated. Nodes can be nested, so we have tree structure we have to navigate. We use a Queue to walk through the nodes in a breadth-first fashion.
@@ -168,7 +168,7 @@ I like to use as many functional programming techniques as I can in C# these day
If you're not familiar with breadth-first tree traversals, it's not too complicated. What we do first is get all the nodes at the top level (in our case, all the nodes that are direct children of the catalog we pass in) and put them in the queue. Then, we iterate through each of the nodes we put in the queue and add their child nodes to the queue. We do this until we run out of nodes to process in the queue which indicates we've gone through all nodes in the tree. If you're not familiar with breadth-first tree traversals, it's not too complicated. What we do first is get all the nodes at the top level (in our case, all the nodes that are direct children of the catalog we pass in) and put them in the queue. Then, we iterate through each of the nodes we put in the queue and add their child nodes to the queue. We do this until we run out of nodes to process in the queue which indicates we've gone through all nodes in the tree.
{% highlight csharp %} ```csharp
public class CatalogSystemNodes : IEnumerable<CatalogNodeDto.CatalogNodeRow> public class CatalogSystemNodes : IEnumerable<CatalogNodeDto.CatalogNodeRow>
{ {
private readonly CatalogSystemNodeEnumerator _enumerator; private readonly CatalogSystemNodeEnumerator _enumerator;
@@ -267,14 +267,14 @@ public class CatalogSystemNodeEnumerator : IEnumerator<CatalogNodeDto.CatalogNod
_current = Option<CatalogNodeDto.CatalogNodeRow>.None; _current = Option<CatalogNodeDto.CatalogNodeRow>.None;
} }
} }
{% endhighlight %} ```
### CatalogSystemEntries Iterator ### CatalogSystemEntries Iterator
Since entries cannot be arrange in a nested fashion, this iterator is a little less complicated than the nodes iterator. All we do is take in a catalogId and a catalogNodeId and retrieve all the entries below the given node ID, passing them to you one at a time as you call MoveNext(). Since entries cannot be arrange in a nested fashion, this iterator is a little less complicated than the nodes iterator. All we do is take in a catalogId and a catalogNodeId and retrieve all the entries below the given node ID, passing them to you one at a time as you call MoveNext().
The only mildly complex thing here is that we use a `Lazy<T>` so that we're not retrieving the entries immediately when you instanstiate the IEnumerator. We only load the entries when you MoveNext() and access Current which indicates you really do want some entries. The only mildly complex thing here is that we use a `Lazy<T>` so that we're not retrieving the entries immediately when you instanstiate the IEnumerator. We only load the entries when you MoveNext() and access Current which indicates you really do want some entries.
{% highlight csharp %} ```csharp
public class CatalogSystemEntries : IEnumerable<CatalogEntryDto.CatalogEntryRow> public class CatalogSystemEntries : IEnumerable<CatalogEntryDto.CatalogEntryRow>
{ {
private readonly CatalogSystemEntryEnumerator _enumerator; private readonly CatalogSystemEntryEnumerator _enumerator;
@@ -355,14 +355,14 @@ public class CatalogSystemEntryEnumerator : IEnumerator<CatalogEntryDto.CatalogE
private Lst<CatalogEntryDto.CatalogEntryRow> GetEntries() private Lst<CatalogEntryDto.CatalogEntryRow> GetEntries()
=> _catalogSystem.GetCatalogEntriesDto(_catalogId, _catalogNodeId).CatalogEntry.Freeze(); => _catalogSystem.GetCatalogEntriesDto(_catalogId, _catalogNodeId).CatalogEntry.Freeze();
} }
{% endhighlight %} ```
### CatalogSystemEntryMetaObjects Iterator ### CatalogSystemEntryMetaObjects Iterator
The MetaObjects iterator is a different than the other iterators in that it doesn't really iterate through a list or tree of MetaObjects. Instead, it iterates through all fo the MetaObject instances for a particular entry--one instance for reach culture available for the catalog. The MetaObjects iterator is a different than the other iterators in that it doesn't really iterate through a list or tree of MetaObjects. Instead, it iterates through all fo the MetaObject instances for a particular entry--one instance for reach culture available for the catalog.
So, as you'll see in the code below, one of the first things we do is grab all of the languages for the catalog so that we know what we need to interate through. So, as you'll see in the code below, one of the first things we do is grab all of the languages for the catalog so that we know what we need to interate through.
{% highlight csharp %} ```csharp
public class CatalogSystemEntryMetaObjects : IEnumerable<(MetaObject metaObject, MetaDataContext metaDataContext)> public class CatalogSystemEntryMetaObjects : IEnumerable<(MetaObject metaObject, MetaDataContext metaDataContext)>
{ {
private readonly CatalogSystemEntryMetaObjectsEnumerator _enumerator; private readonly CatalogSystemEntryMetaObjectsEnumerator _enumerator;
@@ -449,14 +449,14 @@ public class CatalogSystemEntryMetaObjectsEnumerator : IEnumerator<(MetaObject m
.Map(lr => new CultureInfo(lr.LanguageCode)) .Map(lr => new CultureInfo(lr.LanguageCode))
.Freeze(); .Freeze();
} }
{% endhighlight %} ```
## Warning ## Warning
Even though the above code will give you the convenience of iterating through your entire EPiServer catalog(s), be warned! You could easily forget what the IEnumerators really do above and do something like this: Even though the above code will give you the convenience of iterating through your entire EPiServer catalog(s), be warned! You could easily forget what the IEnumerators really do above and do something like this:
{% highlight csharp %} ```csharp
// REALLY BAD CODE, DON'T DO // REALLY BAD CODE, DON'T DO
List<(MetaObject metaObject, MetaDataContext mdc)> allTheMetaObjects = _catalogSystem.AllCatalogSystemEntryMetaObjects(mdc).ToList(); List<(MetaObject metaObject, MetaDataContext mdc)> allTheMetaObjects = _catalogSystem.AllCatalogSystemEntryMetaObjects(mdc).ToList();
{% endhighlight %} ```
I hope you see the danger of this. If you have a large catalog, you're loading the ENTIRE set of MetaObjects into memory in your `allTheMetaObjects` list. This probably won't be good for your application. If you have a small catalog, this might not be a big deal. But, keep this in mind! I hope you see the danger of this. If you have a large catalog, you're loading the ENTIRE set of MetaObjects into memory in your `allTheMetaObjects` list. This probably won't be good for your application. If you have a small catalog, this might not be a big deal. But, keep this in mind!