tag:blogger.com,1999:blog-91164265555559776092024-02-08T20:20:00.104+01:00.Net, Ajax, JavaScript StuffDamianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.comBlogger7125tag:blogger.com,1999:blog-9116426555555977609.post-36729084577668901422011-07-14T14:42:00.004+02:002012-03-07T18:23:56.524+01:00Non expected exception on IPAddress.TryParseLately, for the one of our client we implemented a functionality which uses Geo Location as a basic visitor recognition. The problem appeared after the functionality had been promoted to the live environment - it simple did not work. After a quick investigation we founded that the problem is caused by <i>Akamai </i>which acts as a proxy for whole domain.<div><br /></div><div>The solution itself is pretty simple. <i>Akamai </i>can be configured so that it sends additional <i>Http Request Header</i> with original <i>IP</i>. I just thought that some basic validation on this header value would be great, so I have added something like code below:</div><div><div style="border-top-color: rgb(0, 0, 128); border-right-color: rgb(0, 0, 128); border-bottom-color: rgb(0, 0, 128); border-left-color: rgb(0, 0, 128); border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; "><div style="background-color: rgb(255, 255, 255); max-height: 500px; overflow-x: auto; overflow-y: auto; padding-top: 2px; padding-right: 5px; padding-bottom: 2px; padding-left: 5px; "><div style="text-align: left; "><span> </span></div><div style="text-align: left; "><span style="font-family: 'Courier New', Courier, monospace; font-size: 10pt; white-space: nowrap; color: rgb(0, 0, 255); "> var</span><span class="Apple-style-span"><span class="Apple-style-span" style="white-space: nowrap;"> headerIp = request.Headers[</span></span><span style="font-family: 'Courier New', Courier, monospace; font-size: 10pt; white-space: nowrap; color: rgb(163, 21, 21); ">"True-Client-IP"</span><span class="Apple-style-span"><span class="Apple-style-span" style="white-space: nowrap;">];</span></span></div><div style="font-family: 'Courier New', Courier, monospace; font-size: 10pt; white-space: nowrap; text-align: left; "> <span style="color: rgb(43, 145, 175); "> IPAddress</span> akamaiIpAddress = <span style="color: rgb(43, 145, 175); ">IPAddress</span>.None;</div><div style="font-family: 'Courier New', Courier, monospace; font-size: 10pt; white-space: nowrap; text-align: left; "> <span style="color: rgb(0, 0, 255); "> var</span> isValidIp = <span style="color: rgb(43, 145, 175); ">IPAddress</span>.TryParse(headerIp, <span style="color: rgb(0, 0, 255); ">out</span> akamaiIpAddress);</div></div></div></div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(255, 255, 255); font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 13px; font-weight: bold; "></span></div><div>As you can see I laveraged on IpAddress class to determine whether sent header is correct. The problem was that if there was no header I had had the exception on that line. Why? The answer is very simple, and very unexpected - you can not pass null as a first parameter. I changed this line slightly in the following manner:</div><div><br /></div><div><div style="border-top-color: rgb(0, 0, 128); border-right-color: rgb(0, 0, 128); border-bottom-color: rgb(0, 0, 128); border-left-color: rgb(0, 0, 128); border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; font-family: 'Courier New', Courier, monospace; font-size: 10pt; "> <div style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); max-height: 500px; overflow-x: auto; overflow-y: auto; padding-top: 2px; padding-right: 5px; padding-bottom: 2px; padding-left: 5px; white-space: nowrap; "><span style="color:#0000ff"> var</span> headerIp = request.Headers[<span style="color:#a31515">"True-Client-IP"</span>] ?? <span style="color: rgb(0, 0, 255); ">string</span>.Empty;</div></div></div><div><br /></div><div>and problem disappeared. I always thought that <i>TryParse </i>method on any object should swallow any exception, because it is expected from it. This is one of the most deceiving thing I have met in .NET. Does anyone know if any other <i>TryParse </i>method potentially throws exceptions as well?</div><div><br /></div><div><div> </div></div>Damianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.com1tag:blogger.com,1999:blog-9116426555555977609.post-39710809404892633132011-05-23T10:00:00.001+02:002012-03-07T18:24:50.969+01:00Integrate Sitecore.Logging with Castle Windsor<b><span class="Apple-style-span"><div><b><span class="Apple-style-span"><br /></span></b></div>Abstract</span></b><div><span class="Apple-style-span"><span class="Apple-tab-span" style="font-weight: bold; white-space: pre; "> </span>A couple of months ago I started using <a href="http://en.wikipedia.org/wiki/Dependency_Injection">Dependency Injection</a> pattern in my projects more consciously and extensively. Initially it was not easy and comfortable, however I found it very profitable and useful. I picked <a href="http://docs.castleproject.org/Windsor.MainPage.ashx">Windsor</a> as a Inversion of Control container. In the same time <a href="http://www.sitecore.net/">Sitecore</a> had come along as a new Web CMS platform in <a href="http://www.cognifide.com/">Cognifide</a> range. As a natural consequence those two got married in my projects.</span></div><div><span class="Apple-style-span"><br /></span></div><div><b><span class="Apple-style-span">The issue</span></b></div><div><span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre; "> </span>T<span class="Apple-style-span">he first problem I encountered was a logging issue. I'm using the Logging Facility so that I don't need reference to <i>log4net </i>library, using <i>ILogger </i>from <i>Castle.Core.Logging</i> namespace. Using this facility has a big advantage - Windsor resolves current logger context automatically for maintained classes, so that you don't have to worry about it. If you would like to obtain current logger directly from container you can resolve <i>ILoggerFactory,</i> which creates a logger instance for you. However, this is not a case here. The case was that while everything seemed to be fine, no logs appeared, moreover Windsor always returned a default<i> </i>logger.</span></span></div><div><span class="Apple-style-span"><br /></span></div><div><span class="Apple-style-span"><span class="Apple-tab-span" style="white-space:pre"> </span>After some investigation I finally found the reason - apparently Sitecore guys took whole <i>log4net </i>project as is, changed it according to their requirements (please note that there are some additional configuration features in Sitecore <i>log4net </i>logging configuration section) and finally embraced it as a <i>Sitecore.Logging</i> library. This causes that <i>Windsor </i>is unable to create any logger instance, because it uses full class name to resolve types (note that there is no <i>log4net </i>library anymore, you have <i>Sitecore.Logging</i> instead).</span></div><div><span class="Apple-style-span"><br /></span></div><div><span class="Apple-style-span"><span class="Apple-tab-span" style="white-space:pre"> </span>The solution is simple and pretty straightforward. First you should read great <a href="http://blog.experimentsincode.com/index.php/2010/11/21/288">Michael Edward's post</a> where he explains why logging doesn't work by default. However I would like to go one step ahead and keep my custom functionality "Sitecore free". Therefore I would like to keep using <i>ILogger </i>and by that be free from additional dependency like <i>log4net </i>or <i>Sitecore.Logging</i>. To achieve my goal I had to register my own facility just like in Michael's post, then I had to write my own custom <i>ILoggerFactory <b> </b></i>and <i>ILogger </i>implementations. Both are very simple , for example <i>ILoggerFactory </i>has four methods and one of them is</span></div><div><span class="Apple-style-span"><div><i><b>public ILogger Create(string name)<br /></b></i><i><b>{<br /></b></i><i><b><span class="Apple-tab-span" style="white-space:pre"> </span>return new SitecoreLogger(log4net.LogManager.GetLogger(name));<br /></b></i><i><b>}</b></i></div><div><i><b></b></i>where <i>SitecoreLogger </i>is <i>ILogger </i>implementation. Please note that I pass internal logger in constructor so that I can leverage on it in my implementation. In fact, it is only a wrapper for native logger. <i>ILogger </i>has a number of various methods and each of them is similar to written below:</div><div><div><i><b>public void Error(string message, Exception exception)<br /></b></i><i><b>{<br /></b></i><i><b><span class="Apple-tab-span"><span class="Apple-tab-span" style="white-space: pre; "> </span></span>InnerLogger.Error(message, exception);<br /></b></i><i><b>}</b></i></div></div><div>To use it you have to add a custom facility, the simplest way is doing that from code, where you simply indicate that logger should be created by a custom factory:</div><div><i><b>container.AddFacility<loggingfacility>(p => p.LogUsing</loggingfacility></b></i><i><b><loggingfacility><aaa><sitecoreloggerfactory><sitecoreloggerfactory><span class="Apple-style-span" style="font-style: normal; font-weight: normal; "><i><b><loggingfacility><span class="Apple-style-span" style="font-style: normal; font-weight: normal; "><i><b><loggingfacility><SitecoreLoggerfactory</loggingfacility></b></i></span></loggingfacility></b></i></span></sitecoreloggerfactory></sitecoreloggerfactory></aaa></loggingfacility></b></i><i><b><loggingfacility><aaa><sitecoreloggerfactory><sitecoreloggerfactory><span class="Apple-style-span" style="font-style: normal; font-weight: normal; "><i><b><loggingfacility>></loggingfacility></b></i></span></sitecoreloggerfactory></sitecoreloggerfactory></aaa></loggingfacility></b></i><i><b><loggingfacility><aaa><sitecoreloggerfactory><sitecoreloggerfactory>().WithAppConfig());</sitecoreloggerfactory></sitecoreloggerfactory></aaa></loggingfacility></b></i></div><div>where <i>container </i>is a <i>IWindsorContainer </i>instance, and <i>log4net </i>configuration is in <i>web.config</i> file. You can register it like Michael proposed in his post from configuration file as well.</div></span></div><div><b><span class="Apple-style-span">Conclusion</span></b></div><div><span class="Apple-style-span"><span class="Apple-tab-span" style="font-weight: bold; white-space: pre; "> </span>Solution above allows me to use logging in a loosely coupled way, and keep my custom functionalities as intended - clean and free from unnecessary dependencies. This code is fully open source so f<span class="Apple-style-span">eel free to <a href="http://boss.cognifide.com/~damian_kulik/logger.zip" onclick="javascript: pageTracker._trackPageview('/LoggerIntegration');">download and use it</a> or adjust it in your project.</span></span></div><div><span class="Apple-style-span"><span class="Apple-style-span"><br /></span></span></div><div><b><span class="Apple-style-span">Refrences</span></b></div><div><ol><li><span class="Apple-style-span"><a href="http://en.wikipedia.org/wiki/Dependency_Injection">http://en.wikipedia.org/wiki/Dependency_Injection</a></span></li><li><a href="http://devlicio.us/blogs/casey/archive/2008/06/18/logging-with-castle-windsor-the-logging-facility-and-log4net.aspx"><span class="Apple-style-span">http://devlicio.us/blogs/casey/archive/2008/06/18/logging-with-castle-windsor-the-logging-facility-and-log4net.aspx</span></a></li><li><a href="http://blog.experimentsincode.com/index.php/2010/11/21/288"><span class="Apple-style-span">http://blog.experimentsincode.com/index.php/2010/11/21/288</span></a></li><li><a href="http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart1.aspx"><span class="Apple-style-span">http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart1.aspx</span></a></li><li><a href="http://docs.castleproject.org/Windsor.MainPage.ashx"><span class="Apple-style-span">http://docs.castleproject.org/Windsor.MainPage.ashx</span></a></li><li><a href="http://stackoverflow.com/questions/4419690/register-castle-windsor-logging-facility"><span class="Apple-style-span">http://stackoverflow.com/questions/4419690/register-castle-windsor-logging-facility</span></a></li><li><a href="http://logging.apache.org/log4net/"><span class="Apple-style-span">http://logging.apache.org/log4net/</span></a></li></ol></div><div><span class="Apple-style-span"><br /></span></div><div><span class="Apple-style-span"><br /></span></div><div><span class="Apple-style-span"><br /></span></div><div><span class="Apple-style-span"><br /></span></div>Damianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.com1tag:blogger.com,1999:blog-9116426555555977609.post-38656540175708995182010-03-15T22:16:00.000+01:002010-04-03T10:00:31.521+02:00Mental spring's cleaningToday, I'm not going to introduce anything technical tips or features. I'd like to write a few sentences about (not)using design patterns and good practises.<br />I'd like to review my habits, developers' habits, but only mine?<br /><br />Recently, I have read two fantastic blog's entries:<br />1. Ayende Rahien's <a href="http://ayende.com/Blog/archive/2010/02/20/nice-process-but-what-about-the-engineering-bits.aspx">Nice process but what about the engineering bits</a><br />2. Udi Dahan's <a href="http://www.udidahan.com/2010/03/07/on-small-applications/">On small application</a><br />and I have started to have more deeper thoughts (which I'm always trying to avoid - the headache is terrible after that ;-)) about my profession and projects I have participated.<br /><br />It's never a good time to make negative comments and give an instructive notes, but sometimes its a necessity to say a few bitter words and have moment of reflection. <br /><br />In various discussions I am constantly hearing and reading who is more agile, how to improve the process, how to make each of iteration/sprint in process more efficient and how to meet tight deadlines... but, are those discussions should be the most important ones for developer? Why there is so many opinions and debates about the process if we don't have influence on time-frame and requirements? In my opinion, discussions are not going in the right direction for majority of us. Each of the process:Agile, Kanban, XP, RUP; is good enough to design and create high-quality software as long as developers don't have to bother about it, just using him properly.<br />Maybe I don't get it, but I worked with two of them which are drastically different, but still the main quallity difference between them was made by people - their knowledge, commitment, teamwork and attitude bring much more than MS Project diagram or white cards well-organised on the whiteboard.<br /><br />Instead of it there are some things that seems to be lost and forgotten these days. In my opinion more important and worth to be discussed. Things that makes my profession so inspiring and which can seriously damage my family life. Designs patters and best practises... sounds familiar? <br />So why I feel that we aren't remember the simple principles of object oriented art? <br />Why we aren't improving and refactoring our code which is our only real value we can really rely on?<br />Please ask yourself when did you use some of design patterns last time (please leave the Singleton in peace, because in that case the issue is rather in the second side)? <br />Please ask yourself when did you consider the single resposibility principle during developing some new functionality? <br />When did you consider the loose coupling principle when you had adding some dependency lately?<br />Please ask yourself when did you learn some new features last time? <br />Which new fancy library have you tried? <br />When have you tried to do your tasks better/different that usual?<br /><br />My consience doesn't look too good. Most of answers above sounds 'no' for me. I can say more here - it is a pretty normal that we feel a bit unconfortable with the code we wrote sometime, two or three years ago. But I, in fact, I found some code I am shamed of which is no older than two or three months... I have to use svn's blame because I couldn't believe that I wrote it... very sad but true... I have this terrible headache again now...<br /><br />The winter is ending and the sun is faintly shaning from behind the clouds makes days better and better. I think there is a perfect moment to change things are they used to be. So I have decided to start from my own yard and make a big spring cleaning in my mental working environment and promise myself a few important things:<br /><br />1. <span style="font-weight:bold;">No more comfortable</span> and quick, but simply bad designed and dubious quality <span style="font-weight:bold;">solutions</span>. Even if I am faced with a simple thing, even if its only once, even if its only for now.<br />2. <span style="font-weight:bold;">No more code without any comments</span>, both a documentation style ones and a hint style ones.<br />3. <span style="font-weight:bold;">I will start to use unit tests as a one of my common way to develop things</span>, maybe not as much as I should, but like it used to say ex-coach of our national football's team Leo B. "Step by Step", one by one to make a progress in this area.<br />4. <span style="font-weight:bold;">I will spend some percent of my working hours actually refactoring</span> the code and update the assumed flow and model, because what let us be more professional and mature than when our visions become materialized as predicted and designed?<br />5. I begin to do the task of <span style="font-weight:bold;">considering how to do it</span> rather than when I do it.<br /><br />I hope that I will look at this list this fall and I will be a proud that in two or three points I made a progress...Damianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.comtag:blogger.com,1999:blog-9116426555555977609.post-71682587129272866042009-07-21T14:46:00.000+02:002009-07-24T19:12:21.903+02:00Script and styles optimizer for ASP.NET Part1<h4>Abstract</h4><br />Since project I'm working on became stable we've started to optimise it. Naturally one of the main aims in site optimisation is to minimize load bandwidth and minimize request count between clients and server. I started digging about zipping static content and combining it. Then I hit on two great post which inspired me to my work. You can find them <a target="_blank" href="http://www.codeproject.com/KB/aspnet/AspNetOptimizer.aspx" onclick="pageTracker._link(this.href); return false;">here</a> and <a target="_blank" href="http://geekswithblogs.net/rashid/archive/2007/07/25/Combine-Multiple-JavaScript-and-CSS-Files-and-Remove-Overheads.aspx" onclick="pageTracker._link(this.href); return false;">here</a>. Thanks a lot for those posts!<br /><br />Especially the first one impressed me. In the beginning I wanted to just use it, but then I realized that I need a little more flexible and extensible solution.<br /><br />My requirements were:<br />1. Ability to pass css and js files as a single request (per type).<br />2. Ability to zip content.<br />3. Ability to cache content.<br />4. Ability to configure feature from both configuration file and code.<br />5. Ability to dynamically adding and removing content (both declaratively and imperatively, by removing I mean that it's possible to omit some part of content on particular site.<br />6. Put embedded scripts (*.axd) into combined and zipped resources as well.<br />7. Enclose it as reusable and plug-and-play project.<br /><br />I've decided to follow great idea of Moiz Dhanji (thank you again) and I extended the ScriptManager control. Later I've noticed that it's good to extend ScriptManagerProxy cotrol as well.<br />Based on all of those requirements and two mentioned blog posts I have created a very useful tool - OptimisedScriptManager. If you are interesting in it or you are looking for similar solution you can download and try it from <a href="http://boss.cognifide.com/~damian_kulik/Cognifide.EPiServerControls.OptimisedScriptManager.dll" alt="Cognifide.EPiServerControls.OptimisedScriptManager.dll" onClick="javascript: pageTracker._trackPageview('/OptimisedScriptManager');">here</a>.<br /><br /><h4>Using Instructions</h4><br />1. Add reference to "Cognifide.EPiServerControls.OptimisedScriptManager.dll" in your web application. <br /><br />2. In web.config (under the <pages> section in <controls> collection) register optimised control:<br /><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><span style="color: blue;"><</span><span style="color: #a31515;">add</span><span style="color: blue;"> </span><span style="color: red;">assembly</span><span style="color: blue;">=</span>"<span style="color: blue;">Cognifide.EPiServerControls.OptimisedScriptManager</span>"<span style="color: blue;"> </span><span style="color: red;">namespace</span><span style="color: blue;">=</span>"<span style="color: blue;">Cognifide.EPiServerControls.OptimisedScriptManager.UI</span>"<span style="color: blue;"> </span><span style="color: red;">tagPrefix</span><span style="color: blue;">=</span>"<span style="color: blue;">Optimised</span>"<span style="color: blue;">/></span></p></div><br /><br />3. Now add two GenericHandlers, one will be responsible for css calls, the second one will be responsible for javascripts calls, lets say Css.ashx and Scripts.ashx respectively. Now:<br /><br /> - Please delete both .cs files related to newly added handlers.<br /> - Open Css.ashx and change Class attribute to "Cognifide.EPiServerControls.OptimisedScriptManager.CssHandler" and delete <br />CodeBehind attribute. <br /> - Open Scripts.ashx do the same with one except set Class to "Cognifide.EPiServerControls.OptimisedScriptManager.JavaScriptsHandler"<br />Your markups should now looks like these below:<br /><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><%@ WebHandler Language=<span style="color: #a31515;">"C#"</span> Class=<span style="color: #a31515;">"Cognifide.EPiServerControls.OptimisedScriptManager.CssHandler"</span> %></p></div><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><%@ WebHandler Language=<span style="color: #a31515;">"C#"</span> Class=<span style="color: #a31515;">"Cognifide.EPiServerControls.OptimisedScriptManager.JavaScriptsHandler"</span> %></p></div><br /><br />4. Now if you have ScriptManager somewhere in your code please replace it with <br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><Optimised:OptimizedScriptManager runat=<span style="color: #a31515;">"server"</span> ID=<span style="color: #a31515;">"sm"</span>></p></div><br />if not, please add it in the same terms as common ScriptManager control.<br /><br />5. Rewrite all your scripts and styles declared in page header to the OptimisedScriptManager control, look at the sample below:<br /><br /><Optimised:OptimisedScriptManager runat="server" ID="sm"><br /> <Csses><br /> <Optimised:CssDocumentItem Path="~/Css/Style1.css" MediaType="screen" /><br /> <Optimised:CssDocumentItem Path="~/Css/Style2.css" MediaType="screen" /><br /> <Optimised:CssDocumentItem Path="~/Css/Style3.css" MediaType="print" /><br /> </Csses><br /> <Scripts><br /> <asp:ScriptReference Path="~/Scripts/Script1.js" /><br /> <asp:ScriptReference Path="~/Scripts/Script2.js" /><br /> </Scripts><br /></Optimised:OptimisedScriptManager><br /><br />6. Last thing to do is initialize Opimizer. You can do it both from code or from config file. Please note that you have to initialize tool before first call if you are configure it form code.<br /><br />Imperative example:<br /><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.ScriptsEnabled = <span style="color: blue;">true</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.ScriptsHandlerPath = <span style="color: #a31515;">"/Scripts/Scripts.ashx"</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.ScriptsVersion = <span style="color: #a31515;">"1"</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.ScriptZipContent = <span style="color: blue;">true</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.ScriptsClientCacheDuration = 10;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.ScriptsAppCacheDuration = 1;</p><p style="margin: 0px;"> </p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.CssHandlerPath = <span style="color: #a31515;">"/Css/Css.ashx"</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.CssEnabled = <span style="color: blue;">true</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.CssVersion = <span style="color: #a31515;">"1"</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.CssZipContent = <span style="color: blue;">true</span>;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.CssClientCacheDuration = 10;</p><p style="margin: 0px;"><span style="color: #2b91af;">OptimisedContext</span>.Instance.CssAppCacheDuration = 1;</p></div><br /><br />Declarative example:<br /><br />- SectionGroup registration:<br /><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><sectionGroup name=<span style="color: #a31515;">"OptimisedManager"</span> type=<span style="color: #a31515;">"Cognifide.EPiServerControls.OptimisedScriptManager.Configuration.OptimisedManagerConfigurationSectionGroup, Cognifide.EPiServerControls.OptimisedScriptManager"</span>></p><p style="margin: 0px;"> <section name=<span style="color: #a31515;">"CssOptimised"</span> type=<span style="color: #a31515;">"Cognifide.EPiServerControls.OptimisedScriptManager.Configuration.OptimisedManagerConfigurationSection, Cognifide.EPiServerControls.OptimisedScriptManager"</span> allowDefinition=<span style="color: #a31515;">"Everywhere"</span> /></p><p style="margin: 0px;"> <section name=<span style="color: #a31515;">"ScriptOptimised"</span> type=<span style="color: #a31515;">"Cognifide.EPiServerControls.OptimisedScriptManager.Configuration.OptimisedManagerConfigurationSection, Cognifide.EPiServerControls.OptimisedScriptManager"</span> allowDefinition=<span style="color: #a31515;">"Everywhere"</span> /></p><p style="margin: 0px;"></sectionGroup></p></div><br />- Config entry:<br /><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><OptimisedManager></p><p style="margin: 0px;"> <CssOptimised Enabled=<span style="color: #a31515;">"true"</span> ZipContent=<span style="color: #a31515;">"true"</span> <span style="color: #2b91af;">Version</span>=<span style="color: #a31515;">"5"</span> HandlerPath=<span style="color: #a31515;">"/Scripts/Scripts.ashx"</span> AppCacheDuration=<span style="color: #a31515;">"1"</span> ClientCacheDuration=<span style="color: #a31515;">"10"</span> /></p><p style="margin: 0px;"> <ScriptOptimised Enabled=<span style="color: #a31515;">"true"</span> ZipContent=<span style="color: #a31515;">"true"</span> <span style="color: #2b91af;">Version</span>=<span style="color: #a31515;">"7"</span> HandlerPath=<span style="color: #a31515;">"/Css/Css.ashx"</span> AppCacheDuration=<span style="color: #a31515;">"1"</span> ClientCacheDuration=<span style="color: #a31515;">"10"</span> /></p><p style="margin: 0px;"></OptimisedManager></p></div><br /><br /><h4>Important notes</h4><br />Optimizer:<br />- ignores script blocks and startup scripts.<br />- does not affect AJAX<br />- cares about MicrosoftAjax and MicrosoftAjaxToolkit scripts<br />- will generate separate content for each combination of scripts/styles so you don't have to worry about placing various scripts and styles on various pages<br />- generates separate <script> tag for each MediaType<br />- if you use relative paths in your styles place Css.ashx in the same folder as styles, otherwise url to images will be broken<br />- you can mix tool initialization between config file and code.<br /><br /><h4>Future work</h4><br />First of all I would like to write the same feature in ASP.NET MVC or adjust the existing one, I'm really looking forward to start doing it.<br />There is still a little work to do in this optimiser as well:<br /><ul><br /><li> Before all I want to automate capturing calls, by registering custom UrlRewriter.</li><br /><li>Fact, that css handler has to be placed in css folder isn't good, so the tool which switch the url included in css files will be huge benefit</li><br /><li> I'm thinking about capturing script services proxy, startup scripts and combining them as well.</li><br /><li> Caching part could be improved.</li><br /><li> Logging part could be improved (added ;)).</li><br /></ul><br /><br /><h4>What will be in part 2</h4><br />In this part which I hope publicate in next week I explain how optimizer works internally and I'll give an intructions how to:<br /><br />- use OptimisedManagerProxy control (basically if you used ScriptManagerProxy before this is pretty much the same)<br />- add styles and scripts from embeded resources<br />- make file ignored for some pages (using OptimiseManagerProxy and IsIgnored attribute) <br />And also how the tool works internally, which is not a big secret when you have a reflector:), and why Script.ashx is called twice - second time with empty parameters.<br /><br /><h4>Summary</h4><br />Optimizer is a simple and ready to use tool. It minimize both bandwidth and requests which have huge impact on loading time and user experience. This solution isn't perfect, but it works currently in really big project. I will apprietiate your feedback.Damianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.comtag:blogger.com,1999:blog-9116426555555977609.post-46592628635973010812009-04-09T16:12:00.001+02:002009-05-04T17:08:33.376+02:00Tricky recursive loop and power of loggingRecently I was working on some import functionality which was written earlier by third person. I had to move some data between two separate systems and I was assured that tool provided to me was working fine. So, yes it worked, but processing the 1MB Xml file took him about 30 minutes! <br />God, I know that complicated operations like creating, modifying, managing some big structures can last long, but why it took so incredibly long? <br /><br />I've started coming to terms with the processing time, but then for completely different reason I have added some logging. It was very simple, I logged just most important things - successful and failed imports. I ran tool, and after another half hour I started to browse my log file. What I've noticed first was that log file had over 8MB, it was surprising, but I left it and started to look for failed updates (which interested me then).<br /><br />And then flash of inside! Each thing that should be updated and saved once, in fact was updated and saved about hundred of times. So I ran into code and than I found that method: <br /><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"> <span style="color: blue;">protected</span> <span style="color: blue;">void</span> ProcessNodes(<span style="color: #2b91af;">XmlNodeList</span> nodelist, <span style="color: blue;">string</span> culture)</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < nodelist.Count; i++)</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: #2b91af;">XmlNode</span> node = nodelist[i];</p><p style="margin: 0px;"> <span style="color: blue;">if</span> (node.Name == <span style="color: #a31515;">"page"</span>)</p><p style="margin: 0px;"> ProcessNode(node, culture);</p><p style="margin: 0px;"> <span style="color: blue;">if</span> (node.HasChildNodes)</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: blue;">for</span> (<span style="color: blue;">int</span> i2 = 0; i2 < node.ChildNodes.Count; i2++)</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: blue;">if</span> (node.ChildNodes[i2].Name == <span style="color: #a31515;">"page"</span>)</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> ProcessNode(node, culture);</p><p style="margin: 0px;"> ProcessNodes(node.ChildNodes, culture);</p><p style="margin: 0px;"> }</p><p style="margin: 0px;"> }</p><p style="margin: 0px;"> }</p><p style="margin: 0px;"> }</p><p style="margin: 0px;"> }</p></div><br />Many of you see it immidietaly, but when you browse somebody's code which has more than five lines and didn't analyze that line by line, then you propably going to miss it. The problem with that code is that its not a infinity loop, its actually works, but really, really slow.<br />Each element is saved multiple times, in fact as many times as many children it has, and additional one unnecessary time inside the loop. So, for node which has 5 childrens, 5 siblings and which parent has 3 siblings this node will be updated and saved about 75 times!!!<br />Yeah, that was sneaky:)<br /><br />I learned two thing from there:<br /><br /><b>1. Be careful even when you do a trivial things.</b> The easiest things are the most difficult to to find, because normally you would just skip that bit thinking, 'oh, another loop...'. <br /><b>2. Always log your actions.</b> Simple log file contains more informations than you can image. <br /><br />Oh, actually there's one more... You should never trust others code:PDamianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.comtag:blogger.com,1999:blog-9116426555555977609.post-88874639661998182472009-03-06T13:35:00.000+01:002009-03-06T18:45:59.895+01:00Inheritance in JavaScriptA few days ago I had to implement multi-searcher functionality in javascript.<br />It was something like a box with three searchers. You may pick searcher (i.e. Google, Wikipedia or Yahoo), enter the phrase, click Search button and results were shown below.<br /><br />This task was perfect to use a base class for all searchers an then each type<br />of searcher as derived class. Yes, indeed, but how would you do do it in javascript?<br /><br />I don't wanna talk how much time I spent on it, but finally I have found very simple and pretty obvious solution.<br /><br />First of all we create a base function/class<br /><br />     function BaseClass() {}<br />     BaseClass.prototype =<br />     {<br />         type: "BaseClass",<br /><br />         GetType: function() { return this.type; },<br /><br />         WriteType: function() { document.writeln(this.GetType()); }<br />     }<br /><br />This is rather the dummy class, but reffer to my aim.<br />So we have type field there, and two simple methods.<br /><br />Now I can just write derived classes<br /><br />     FirstDerivedClass.prototype = new BaseClass;<br />     FirstDerivedClass.constructor = FirstDerivedClass;<br />     function FirstDerivedClass()<br />     {<br />         BaseClass.call(this);<br />         this.type = "FirstDerivedClass";<br />     }<br /><br />     SecondDerivedClass.prototype = new BaseClass;<br />     SecondDerivedClass.constructor = SecondDerivedClass;<br />     function SecondDerivedClass()<br />     {<br />         this.type = "SecondDerivedClass";<br />     }<br /><br />And thats it!<br />We have a derived class/functions in javascript.<br /><br />     FirstDerivedClass.prototype = new BaseClass;<br /><br />that line assign prototype to FirstDerivedClass.<br /><br />     FirstDerivedClass.constructor = FirstDerivedClass;<br /><br />that line assigns separate contructor to FirstDerivedClass.<br />And in that way<br /><br />     BaseClass.call(this);<br /><br />we can call base class constructor, please note that it is called earlier too (here - FirstDerivedClass.prototype = new BaseClass;), but by using call method we can pass additional arguments to base class if we want to.<br /><br />In that simple way we obtain the inherit-like result.<br />Code executed below<br /><br />     new BaseClass().WriteType();<br />     new FirstDerivedClass().WriteType();<br />     new SecondDerivedClass().WriteType();<br /><br />shows following text on the page<br /><br />     "BaseClass FirstDerivedClass SecondDerivedClass"<br /><br />and that is exactly what I needed and expected.<br />Cheers!Damianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.com2tag:blogger.com,1999:blog-9116426555555977609.post-14993069950604734842008-12-12T16:45:00.000+01:002008-12-16T11:35:57.008+01:00How to ... find some types in applicationThere is no problem with finding some types in a concrete assembly, but recently I got stuck with more general problem. I needed to find some types in a whole application.<br /><br />First concept was to load all assemblies placed in the /bin directory, one by one and then search for it. This should work, but what if somebody change the output folder? Yes, we can get output path from the framework but...<br /><br />Second concept... I've started digging and found another solution, in fact much better then the first one.<br />From AppDomain class we can get collection of all loaded assemblies, but there is one catch - there are not only assembles referenced by the project but also all framework assemblies. If we iterate over them and store our results, it wouldn't be a problem.<br /><br />In example I stored all types which are an interface.<br />I placed source code for that functionality below:<br /><br /><div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">ClassLoader</span></p><p style="margin: 0px;">{</p><p style="margin: 0px;"> <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Type</span>> loadedTypes;</p><p style="margin: 0px;"> <span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Type</span>> LoadedTypes</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: blue;">get</span></p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: blue;">if</span>(loadedTypes == <span style="color: blue;">null</span>)</p><p style="margin: 0px;"> loadedTypes = LoadTypes();</p><p style="margin: 0px;"> <span style="color: blue;">return</span> loadedTypes;</p><p style="margin: 0px;"> }</p><p style="margin: 0px;"> }</p><p style="margin: 0px;"> </p><p style="margin: 0px;"> <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Type</span>> LoadTypes()</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: #2b91af;">Assembly</span>[] assemblies = <span style="color: #2b91af;">AppDomain</span>.CurrentDomain.GetAssemblies();</p><p style="margin: 0px;"> <span style="color: blue;">return</span> (<span style="color: blue;">from</span> tp <span style="color: blue;">in</span> assemblies.SelectMany</p><p style="margin: 0px;"> (assembly => assembly.GetTypes())</p><p style="margin: 0px;"> <span style="color: blue;">where</span> CheckCondition(tp)</p><p style="margin: 0px;"> <span style="color: blue;">select</span> tp).ToList();</p><p style="margin: 0px;"> }</p><p style="margin: 0px;"> </p><p style="margin: 0px;"> <span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">bool</span> CheckCondition(<span style="color: #2b91af;">Type</span> type)</p><p style="margin: 0px;"> {</p><p style="margin: 0px;"> <span style="color: blue;">return</span> type.IsInterface;</p><p style="margin: 0px;"> }</p><p style="margin: 0px;">}</p></div><br /><br />I hope it will be a help for someone,<br />Enjoy<br /><br /><p></p>Damianhttp://www.blogger.com/profile/02395547672128450032noreply@blogger.com0