Luuuukke.NET

Bugs, headache, lost hairs... I love IT

Use JQuery jstree treeview with ASP.NET webforms

clock May 18, 2012 23:28 by author Luuuukke

On a client’s application, the navigation menu is quite huge,  and loaded from multiple web.sitemaps,
using role security through the sitemap provider (securityTrimmingEnabled property).

Until recently, I was using the ASP.NET treeview control to render the menu, but I never liked the fact that it had to postback to be able to save its state,
as the pages can be quite big (lots of forms, grids…), it was slowing down the navigation too much.

So I looked at alternatives, and decided to go with the jstree JQuery plugin : http://www.jstree.com/
In the requirements, saving state was mandatory. Jstree can do that through the JQuery.cookies plugin.

 

In this first part, I’ll talk about the client side implementation,
in next part I’ll explain how I modified the cssfriendly adapter code to rewrite sitemapdatasources as clean <ul><li> html code

 

I will first enumerate the small quirks that I faced:

  • li elements of your menu need to have an ID tag, the ID value can not start with a number
    (I also had problems with an underscore in the tag value, although not 100% verified it was the cause)
  • To avoid weird behavior, set the cookie path to ”/”, else the tree state is saved according to the page path…
  • To activate the url of inner links, you have to remove the UI plugin
  • The jstree has a little flicker effect when rendering…
    To remove it, I added a div arround the treeviews (called “menuWrapper” here), which is hidden by default (style="display: none;")
    and shown after that treeviews are loaded (see the “'bind” call on the 3rd treeview
  • In a multi level treeview, if you close an element, which has childs opened , this element will reopen automaticaly on page refresh…
    You can remove this behavior by adding the option open_parents: false  in the core function.
    There should be a way to automatically close child nodes, with binding the close_node event…. but I  did not succeed…
  •                 .bind("close_node.jstree", function (e) {
                            alert(e.type);
                    })

 

Jquery code

$(function () {
    $("#tvMain")
        .bind("loaded.jstree", function (event, data) {
            $("#menuWrapper").fadeToggle("slow", "linear");
        })
        .jstree({
            themes: { theme: "default", dots: false, icons: false },
            core: { animation: 200, open_parents: false },
            cookies: { cookie_options: { path: '/'} },
            plugins: ["themes", "html_data", "cookies"]
        });
});

 

Html code

            <div id="menuWrapper" style="display: none;">
                    <div id="tvMain">
                        <asp:Literal runat="server" ID="LitMainMenu" EnableViewState="false"></asp:Literal>
                </div>
            </div>

CSS Code

I changed the default icons with msdn style custom icons. Pay attention to set !important on your styles

.jstree-default ins:hover
{
    cursor: pointer;
}
.jstree-default .jstree-open > ins
{
    background: url("../../Media/TreeView/collapse.gif") 3px 3px no-repeat !important;
}
.jstree-default .jstree-closed > ins
{
    background: url("../../Media/TreeView/expand.gif") 3px 3px no-repeat !important;
}
.jstree-icon
{
    background: url("../../Media/TreeView/emptynode.gif") 3px 3px no-repeat !important;
}
#tvMain a:hover
{
    color: red;
}
#tvMain
{
    color: Black;
    font-family: Tahoma;
    font-size: 8pt;
    
}
.jstree-default.jstree-focused {background: transparent !important;}
More on codebehing coding next time…


Minify css and jss files automatically with Visual Studio Web Application Projects

clock April 27, 2012 20:31 by author Luuuukke

Some months ago, I posted info about minifying js & css files automatically, with web deployment projects:
http://www.luuuukke.net/post/minify-css-and-jss-script-with-visual-studio-web-deployment-projects.aspx

 

Now, that I plan to migrate some websites to Azure, I have to migrate my websites to web applications (easy, but quite annoying …)
So, I of course wanted to keep minifying those static files also, with web applications projects..;

I found an excellent article here, about minifying with the Ajax minifier
http://thefrontend.wordpress.com/2012/02/02/minify-javascript-and-css-files-when-publishing-web-applications/
Worth to read, as it explains all steps very clearly.

 

After testing, I preferred to keep using the Yahoo YUI Compressor…
(Got strange results sometimes with the Ajax minifier.)

 

It is in fact quite easy…  all you have to do is:

Edit the application project file with a text editor  (right click the application, “edit xxxx project file”)
(I did it even with the project open in Visual Studio, no problem, VS reloads it after saving in the text editor)


and then add a few lines of code at bottom, under “ </ProjectExtensions>”

The code should be something like:

  <UsingTask TaskName="CompressorTask" AssemblyFile="..\..\..\..\SharedReferences\Yahoo.Yui.Compressor.dll" />
  <Target Name="CompressJsAndCss" AfterTargets="CopyAllFilesToSingleFolderForPackage" Condition="'$(Configuration)'=='Release'">
    <ItemGroup>
      <CssFiles Include="$(_PackageTempDir)\App_Themes\**\*.css;$(_PackageTempDir)\CSS\*.css" />
      <JavaScriptFiles Include="$(_PackageTempDir)\JavaScript\*.js" />
    </ItemGroup>
    <Message Text="Compressing JavaScript and CSS files..." Importance="high" />
    <CompressorTask CssFiles="@(CssFiles)" DeleteCssFiles="No" CssOutputFile="%(rootdir)%(directory)%(Filename).css" 
CssCompressionType="YuiStockCompression" JavaScriptFiles="@(JavaScriptFiles)" ObfuscateJavaScript="FoSho" 
PreserveAllSemicolons="Yeah" DisableOptimizations="Nope" EncodingType="Default" DeleteJavaScriptFiles="No" 
JavaScriptOutputFile="%(rootdir)%(directory)%(Filename).js" LoggingType="ALittleBit" />
  </Target>

You’ll have to adapt the path to YUI compressor (mine is in a folder where I put shared libraries, under source control too)
and also, adapt the files selector up to your needs (values of the “include” parameters of the CSSFiles & JavascriptsFiles nodes)
A few trial & error should bring you the results you wish.

 

The YUI Compressor has lots of options, which you can find here:  http://developer.yahoo.com/yui/compressor/

And, at the time you read this, Visual Studio 2012 will certainly be released, and doing this automatically Winking smile



Unable to start debugging on the web server. Could not start ASP.NET debugging.

clock April 13, 2012 10:23 by author Luuuukke

Visual Studio fail to launch debugging on my local IIS7 webserver, with this error:

image

The responsible is IIS rewrite module…

Visual Studio, when starting up, will attempt to access the URL: /debugattach.aspx

If a rule rewrites / redirect .aspx files, you get this error…

The solution is to add this section to the beginning of your web.config's system.webServer/rewrite/rules section:

<rule name="Ignore Default.aspx" enabled="true" stopProcessing="true">
    <match url="^debugattach\.aspx" />
    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
    <action type="None" />
</rule>

Solution found on http://stackoverflow.com/questions/4653236/unable-to-start-debugging-on-the-web-server-could-not-start-asp-net-debugging-v

(Thanks Kirk !)

 

Edit: I also had to remove the following rules :

<rule name="RemoveTrailingSlashRule1" stopProcessing="true">
    <match url="(.*)/$" />
    <conditions>
     <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
     <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
    </conditions>
    <action type="Redirect" url="{R:1}" />
</rule>

<rule name="LowerCaseRule1" stopProcessing="true">
  <match url="[A-Z]" ignoreCase="false" />
  <conditions>
   <add input="{URL}" matchType="Pattern" pattern=".*/Pictures/.*" ignoreCase="true" negate="true" />
   <add input="{REQUEST_FILENAME}" matchType="Pattern" pattern="^.*\.(axd|asmx|css|gif|jpg|png|js)$" ignoreCase="true" negate="true" />
  </conditions>
  <action type="Redirect" url="{ToLower:{URL}}" />
</rule>


Could not load file or assembly 'AjaxControlToolkit Culture=neutral, PublicKeyToken=or one of its dependencies. The parameter is incorrect…

clock July 11, 2011 21:24 by author Luuuukke

Got this message,  checked all files… deleted the solution file, re-linked all projects & references… nothing was helping.

And this error suddenly came after my computer crashed (overheating, nut that’s another problem).

 

Hey, but wait…. the computer crashed while visual studio was building the solution…
The problem was easily solved by deleting asp.net framework temporary files Smile

 

image



Unable to update the EntitySet

clock June 24, 2011 14:22 by author Luuuukke

If you get this Error with Entity Framework:

Unable to update the EntitySet {EntityName} because it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element to support the current operation.

Just check that the table have a PrimaryKey assigned…
And do not forget to update your datamodel after adding the key.Winking smile



Visual Studio 2010 crashes on exit

clock February 4, 2011 10:07 by author Luuuukke

Visual studio was consistently crashing when exiting, with 2 specifics solutions…
I had to close all documents, collapse all sub projects, and select the solution in the Solution explorer to avoid VS to crash… Steaming mad

image

 

Yesterday, I found the cause: one child class library project was set to compile in asp.Net 2.0,
while all other projects were set to compile for asp.Net 4.0…

image

 

To change the target framework of a class library project,
open its properties,
select the tab “compile”,

go to the advanced options :

image

 

And select the target network:

image

 

That’s all folks Hot smile



Custom Sitemap Provider Localization

clock January 24, 2011 10:06 by author Luuuukke

Sitemap Providers are a nice feature of asp.NET 2.0, especially with the possibilities to develop your own custom providers.

One problem I faced is the ability to localize title, description .. for my custom provider.
After goggling a lot, I found… that I was not alone with that problem, and that nobody had posted the solution online

(The only solutions that I found were quirky fixes, like programmatically parsing the sitemap nodes title at page load, without using the built-in localization system…)

I found tips here .. And the solution is darn easy:

In your custom provider, in the method

Public Overrides Function BuildSiteMap() As System.Web.SiteMapNode

Load your sitemap nodes using the following method

Public Sub New( _
ByVal provider As SiteMapProvider, _
ByVal key As String, _
ByVal url As String, _
ByVal title As String, _
ByVal description As String, _
ByVal roles As IList, _
ByVal attributes As NameValueCollection, _
ByVal explicitResourceKeys As NameValueCollection, _
ByVal implicitResourceKey As String _
)

 

instead of the commonly used method

Public Sub New( _
ByVal provider As SiteMapProvider, _
ByVal key As String, _
ByVal url As String, _
ByVal title As String
)

In my case in use the implicitResourceKey to pass the resource name,
and my custom localization provider (sql resources) does the rest…

Dim node As New SiteMapNode(Me, key, url, title, string.empty, Nothing, Nothing, Nothing, {title resource name})

 

And then tell your application that your custom sitemap is localized by setting the enableLocalization="true"

<siteMap defaultProvider="MyCustomSiteMapProvider" enabled="true">
            <providers>
                    <add name="MyCustomSiteMapProvider" type="MyCustomSiteMapProviderType, MyCustomSiteMapProviderType.dll"  enableLocalization="true"/>
                      </providers>
        </siteMap>
 

 

Edit 30 Jan. : the first visitor coming on a page receives the correct language, but then the sitemap does not localize to the other languages!!!
I gave up, and now I populate the nodes’ text at runtime…

Protected Sub TopMenu_MenuItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.MenuEventArgs) Handles TopMenu.MenuItemDataBound
Dim n As SiteMapNode = CType(e.Item.DataItem, SiteMapNode)
Dim title As String = GetGlobalResourceObject("resource", n.ResourceKey)
e.Item.Text = title 
End Sub


System.DBNull when reading excel file

clock December 12, 2010 17:43 by author Luuuukke

If you get DBNull values when reading an excel fil through Microsoft.Jet.OLEDB provider, although cells contain values
there is a simple trick: add a parameter "IMEX=1" to the connection string, to force the cells to be read as text ...

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=FileName.xls;Extended Properties="Excel 8.0;IMEX=1"

 

 

 



Visual Studio XML IntelliSense for URL Rewrite

clock December 12, 2010 17:30 by author Luuuukke

With the new IIS 7 integrated configuration model, you may want to use the add-in URL rewriting

Unfortunately, Visual Studio intellisense does not natively understand the rewrite tags...
So you need to update the schema.. See http://ruslany.net/2009/08/visual-studio-xml-intellisense-for-url-rewrite-1-1

To install this schema, you will need to execute a C# Script "cscript UpdateSchemaCache.js",

On my windows 7 , I was not able to run that script, and received the error: There is no script engine for file extension "js"

The solution is here:
http://www.winhelponline.com/articles/230/1/Error-There-is-no-script-engine-for-file-extension-when-running-js-files.html

You need to register the jscript.dll and apply and patch...

Enjoy :-)



Automatically encrypt connection strings in web.config

clock September 18, 2010 17:06 by author Luuuukke

Following the recent discovery of this asp.NET security flaw, i checked all my production web.config to set the correct custom errors,
and also to verify that connection strings are encrypted.

As you certainly now, you can do it on the server with the aspnet-regiis.exe command..;
but you have to run it manually, and take care not to upload an unencrypted web.config later... not very practical when you manage dozens of websites...

As there is an easy way to encrypt web.config section programmatically,
i found wise to have the application_start check that the connectionString is encrypted, and do it automatically otherwise...

Sub Application_OnStart()
        
        Dim config As Configuration = WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath)
        Dim section As ConfigurationSection = config.GetSection("connectionStrings")
            If (section.SectionInformation.IsProtected) = False Then
                section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider")
                config.Save()
            End If
                          
End Sub

 

To avoid encrypting the connection on the development server, i simply added a test and a key in the appsettings...

    Sub Application_OnStart()
        
        If ConfigurationManager.AppSettings("AutomaticallyEncryptConnectionStrings") Is Nothing _
        OrElse CType(ConfigurationManager.AppSettings("AutomaticallyEncryptConnectionStrings"), Boolean) = True Then
            
            Dim config As Configuration = WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath)
            Dim section As ConfigurationSection = config.GetSection("connectionStrings")
            If (section.SectionInformation.IsProtected) = False Then
                section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider")
                config.Save()
            End If
        End If

                   
    End Sub

appsettings key :

    <appSettings>
        <add key="AutomaticallyEncryptConnectionStrings" value="false"/>      
    </appSettings>

 

Please note that i used HttpRuntime.AppDomainAppVirtualPath and not  Request.ApplicationPath,
because there is no context available in Application_start when running in integrated mode

 

Now I can again sleep soundly... Wink



Sign in