As documented here on MSDN the PropertyItem object does not have a public constructor.
What to do then when you want to add a property to an image, using Image.SetPropertyItem(..) method?
This post suggests you create some bank of all property items you want, hold it memory and clone from it.
A commenter on that blog suggested using reflection: Get the non-public parameter-less constructor and invoke it. Notable downside for this approach is reliance on internal implementation of the object. True. I'll risk it though.
In my implementation, I added a helper method which simply generates the PropertyItem using System.Activator like so:
public static PropertyItem CreatePropertyItem(int id, int length, short exifType, byte[] buffer)
{
var instance = (PropertyItem)Activator.CreateInstance(typeof(PropertyItem), true);
instance.Id = id;
instance.Len = length;
instance.Type = exifType;
instance.Value = buffer;
return instance;
}
Pretty clean and simple. Under the covers, Activator will use some reflection to create the instance, but would also utilize some caching and speed written by not-me. I like not-me code because it means I don't have to write it.
Since one of my my upcoming talks at http://socalcodecamp.com is on the subject of reflection, this all falls neatly into place.
7e86334c-e378-440a-b70c-7432fc81d955|0|.0
Sometimes I just write code. And sometimes I clean up my code. Most of the times, I focus on the meat of the methods, hacking away at verbose or lengthy flows, re-factoring out common code, trying to untangle overly complex logic etc.
Recently, I noticed that many of the conditional terms I write span very long lines and are a bit cumbersome to read. The reason for that is that many of the variable names are long, or the properties or both and that often the comparison is on a property of an object or member of a collection etc.
So for instance:
if (summerCatalog.Products[0].ProductCategories[0].ParentCategoryID >= 1 && summerCatalog.Products[0].ProductCategories[0].ParentCategoryID <= 4)
{
//...
}
Can become quite long.
Long is not easy to read.
Long is not easy to maintain.
Long is not easy to think through.
What I really wanted to say is if [value] is between [a] and [b].
Of course, one could say "lets just make the variable names shorter". But that flies in the face of self explanatory plain naming. So abbreviating for the sake of short-lineliness (New word! You heard it her first!) is out.
Well, this is just screaming "EXTENSION METHODS" doesn't it?
Here we go then:
/// <summary>
/// Returns whether the value is between the 2 specified boundaries.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">The value to compare</param>
/// <param name="minValueInclusive">The min value (inclusive).</param>
/// <param name="maxValueInclusive">The max value (inclusive).</param>
/// <returns>True if the value is equal to or between the boundaries; False otherwise.</returns>
public static bool Between<T>(this T value, T minValueInclusive, T maxValueInclusive) where T : IComparable<T>
{
if (minValueInclusive.CompareTo(maxValueInclusive) > 0)
{
throw new ArgumentException("minimum value must not be greater than maximum value");
}
return (value.CompareTo(minValueInclusive) >= 0 && value.CompareTo(maxValueInclusive) <= 0);
}
The Between function takes any object which supports IComparable<T> and performs syntactic sugar comparison with the inclusive min and max values.
What's more, it adds a basic sanity check for the comparison. How many times do I do that sanity check in my normal code (!)?
Now the conditional is
if (summerCatalog.Products[0].ProductCategories[0].ParentCategoryID.Between(1, 4))
{
///...
}
At least I don't have to refactor this in my brain while reading.
Sure, you might say, but you could have just de-referenced the deep value and then have a shorter conditional, like so:
Category category = summerCatalog.Products[0].ProductCategories[0];
if (category.ParentCategoryID >= 1 && category.ParentCategoryID <= 4)
{
//...
}Yes - of course - but it adds a line of code, places the burden of reading the very common idiom ( x >= a && x <= b) on me, and I constantly stumble on the lest-than-or-equal vs. less-than and it doesn't check for my boundaries being inadvertently swapped.
So there you have it. A simple extension cuts down your lines of code, makes long text shorter and saves lives. Which begs the question: is this already part of the language - and should it be?
a54628f4-2ccd-44e7-b039-ece0c3807dfc|0|.0
Bing.com as viewed in Google Chrome.
:-)
67032500-4365-4469-ae11-3fab73df3530|0|.0
So I wrote the thing up. Compared with a fairly common alternative, a run of the more type safe and render friendly template took 260 ms to merge 10k iterations vs. 480 ms for the alternative. In addition, the alternative went through almost twice the allocations (meaning more GC would result).
I'm kind of pleased that this is faster than the alternative, but am going to do some more thinking of a better way. A 46% reduction is nice, but it's just under twice as fast. Still, the benefits of a cached template and token/key checking beats the alternative.
Toying with the idea of a strongly typed template leads to a dead end pretty much. Sure, one could dynamically emit a class that exposes the token names as properties, but then how would you bind to these in compile time? since the tokens are NOT known at compile time, the programmer using the class would have to populate a name value pair in some fashion, so that at run time the binding could be made.
//------------------------------------
namespace Nuri.FasterTemplate
{
public interface IFasterTemplate
{
string ID { get; }
void Render(System.IO.TextWriter writer, IRuntimeValues runtimeValues);
IRuntimeValues GetRuntimeValuesPrototype();
}
}
//------------------------------------
namespace Nuri.FasterTemplate
{
public interface IRuntimeValues
{
bool AddValue(string tokenName, string value);
bool AddValues(IEnumerable values);
string[] GetAllowedValues();
IRuntimeValues GetCopy();
bool IsAlowed(string tokenName);
string this[string tokenName] { get; }
string ID { get; }
}
}
//------------------------------------
namespace Nuri.FasterTemplate
{
public static class FasterTempateFactory
{
public static IFasterTemplate GetFasterTemplate(TokenConfiguration config, ref string template)
{
string id = Guid.NewGuid().ToString();
TemplateParts templateParts = processTemplateParts(id, config, ref template);
IRuntimeValues runtimeValuesPrototype = processTokens(id, templateParts);
IFasterTemplate result = new FasterTemplate(id, templateParts, runtimeValuesPrototype);
return result;
}
private static IRuntimeValues processTokens(string id, TemplateParts templateParts)
{
RuntimeValues result = new RuntimeValues(id);
for (int i = 0; i < templateParts.Count; i++)
if (templateParts[i].IsToken)
result[templateParts[i].Value] = string.Empty;
return result;
}
private static TemplateParts processTemplateParts(string id, TokenConfiguration config, ref string template)
{
TemplateParts result = new TemplateParts();
char currentChar;
bool isToken = false;
StringBuilder sbText = new StringBuilder(template.Length / 2);
StringBuilder sbToken = new StringBuilder(64);
for (int idx = 0; idx < template.Length; idx++)
{
currentChar = template[idx];
if (currentChar == config.TokenStartMarker)
{ isToken = true; result.Add(new TemplatePart(sbText.ToString(), false)); sbText.Length = 0; }
else if (currentChar == config.TokenEndMarker) { isToken = false; result.Add(new TemplatePart(sbToken.ToString(), true)); sbToken.Length = 0; } else { if (isToken) sbToken.Append(currentChar); else sbText.Append(currentChar); }
} if (isToken == true) throw new ArgumentException("Template has unclosed token marker"); if (sbText.Length > 0) result.Add(new TemplatePart(sbText.ToString(), false)); return result;
}
}
}
//------------------------------------
namespace Nuri.FasterTemplate
{
internal class FasterTemplate : IFasterTemplate
{
private string _ID;
private TemplateParts _TemplateParts;
private IRuntimeValues _RuntimeValuesPrototype;
internal FasterTemplate(string ID, TemplateParts templateParts, IRuntimeValues runtimeValuesPrototype) { _ID = ID; _TemplateParts = templateParts; _RuntimeValuesPrototype = runtimeValuesPrototype; } public IRuntimeValues GetRuntimeValuesPrototype() { return _RuntimeValuesPrototype.GetCopy(); } public string ID { get { return _ID; } }
public void Render(System.IO.TextWriter writer, IRuntimeValues runtimeValues)
{
if (runtimeValues.ID != this._ID) throw new ArgumentException("The runtime values supplied are not compatible with this template! Ensure you got the runtime values object from the template with ID " + this._ID); for (int i = 0, count = _TemplateParts.Count; i < count; i++)
{
TemplatePart part = _TemplateParts[i]; if (part.IsToken) { writer.Write(runtimeValues[part.Value]); }
else
{
writer.Write(part.Value);
}
}
}
}
}
//------------------------------------
namespace Nuri.FasterTemplate
{
internal class RuntimeValues : Nuri.FasterTemplate.IRuntimeValues
{
private Dictionary<string,string> _AllowedValues;
internal string _ID;
internal RuntimeValues(string ID, int capacity)
{
_AllowedValues = new Dictionary<string, string>(capacity);
_ID = ID;
}
internal RuntimeValues(string ID) : this(ID, 0x10) { }
internal Dictionary<string,string> AllowedValues
{
get { return _AllowedValues; }
}
public string[] GetAllowedValues()
{
string[] result = new string[_AllowedValues.Count];
int i = 0;
foreach (string key in _AllowedValues.Keys)
{ result[i++] = key; }
return result;
}
public bool IsAlowed(string tokenName)
{
return _AllowedValues.ContainsKey(tokenName);
}
public bool AddValue(string tokenName, string value)
{
if (_AllowedValues.ContainsKey(tokenName))
{
_AllowedValues[tokenName] = value;
return true;
}
else
return false;
}
public bool AddValues(IEnumerable values)
{
bool result = true;
foreach (KeyValuePair<string, string> pair in values)
{
result = result && this.AddValue(pair.Key, pair.Value);
}
return result;
}
public string this[string tokenName]
{
get
{
return _AllowedValues[tokenName];
}
internal set
{ _AllowedValues[tokenName] = value; }
}
public IRuntimeValues GetCopy()
{
RuntimeValues result = new RuntimeValues(this._ID, _AllowedValues.Count);
foreach (string key in _AllowedValues.Keys)
result.AllowedValues[key] = string.Empty;
return result;
}
public string ID
{
get { return _ID; }
}
}
}
//------------------------------------
namespace Nuri.FasterTemplate
{
internal struct TemplatePart
{
public bool IsToken;
public string Value;
public TemplatePart(string value, bool isToken)
{
this.Value = value;
this.IsToken = isToken;
}
}
}
//------------------------------------
namespace Nuri.FasterTemplate
{
class TemplateParts : List<TemplatePart> { }
}
//------------------------------------
namespace Nuri.FasterTemplate
{
public struct TokenConfiguration
{
public readonly char TokenStartMarker;
public readonly char TokenEndMarker;
public TokenConfiguration(char tokenStartMarker, char tokenEndMarker)
{
TokenStartMarker = tokenStartMarker;
TokenEndMarker = tokenEndMarker;
}
}
}
6a6979f0-1f94-441a-8241-3dcfab162c78|0|.0
Categories: General, Web
Posted by
nurih on
2/12/2009 10:25 AM |
Comments (0)
You know you are a geek when things like this seem of any importance.
It may comfort you to know that there are others who are excited about the buzz. It may disturb you. Make of it what you will:
On Friday,
February 13th 23:31:30 UTC 2009 the time_t structure would contain the the number
1234567890
The time_t is measures seconds past midnight of January 1 1970
(see
Unix Epoc, POSIX time etc)
You might celebrate UTC time - those of you not stuck in traffic in New York or at work in California. Or just do it according to your time zone: raise a toast, save some doughnuts from doughnut-Friday or look at the sky or do triple click an icon or something.
Here's a little java script to sneak onto your website which shows the time and the countdown:
<script language="javascript" type="text/javascript">
function onTick()
{
var t = Math.floor( ((new Date()).getTime()) /1000);
var remaining = (1234567890 - t);
var display = "Now: " + t + ": " + remaining + " Sec. to 1234567890 (local time zone).";
document.getElementById("_ShowTime").innerHTML = display;
}
setInterval('onTick()', 1000);
</script>
<div id="_ShowTime" style="height: 1.1em; color: white; background-color: navy; font-weight:bolder; border: dashed 1px blue;"></div>
9a13223c-616b-467c-bb7b-411a685b1fa1|0|.0
Categories: General, Web
Posted by
nurih on
2/1/2009 9:41 AM |
Comments (0)
Frustrated with square looking web pages, many web designers look to Flash. In addition to freedom of graphic expression, Flash brings interaction and transition effects which are difficult or impossible to duplicate. Why then shouldn't all websites be Flash laden? Several reasons pop to mind:
- Loading speed: Way too often, flash movies load complex graphics, forcing the viewer to stare at some progress bar. For people who want to quickly access information this is a huge turn off. A "skip intro" sometimes viewed as lame.
- SEO: Flash based sites rarely are digestible or well ranked by search engines. You use flash – you lose top slots in natural search results. It's that simple
- Form over content: Flash designs - as beautiful and engaging as they may be – all too often sacrifice text and information quantity in order to not disturb the layout or fit within the containing graphics. Again, ranking will suffer (low authority), viewers seeking comprehensive data will navigate away or become frustrated attempting to dig up more details by clicking every button and link in the movie.
- Cost: Although many good web designers can produce Flash movies, the good ones are fewer and more expensive. The problem compounds with natural workplace attrition. The ability to modify the original design, extend the site or give the site a "facelift" becomes constrained or expensive. All too often the original design does not lend itself well to rearrangement or extension.
- QA: Automated testing of Flash UI sites is difficult or impossible because the results may not be capture-able by testing tools – and that's in the good case where the inputs are automatable. Unit testing for ActionScript is available by supporting frameworks these days, but finding implementations which include continuous integration is still rare.
- Ease of use: Often, the design focus reflects the author's perspective. As long as the viewer wants to view information the way the designer does, everything flows well. Once the viewer wants to navigate in a different way, all bets are off.
- Stickiness: By far, one of the more compelling reasons for having used a Flash based site was to engage the viewer and strengthen the brand. The delivery on the promise is a bit mixed. Although some interaction does increase the stickiness of the site, other designs may suffer from slow load and skimpy content actually detracting from the overall perceived quality.
If while reading the points mentioned above you think to yourself "It seems that many of the points indicate poor design – not a technology limitation" you are right, and I couldn't agree with you more.
Yet a good amount of sites out there suffer from these issues. Most of these sites would have been better served producing an HTML / DHTML / CSS + Ajax etc. In fact, my motivation for writing this came from a restaurant website I visited today. While scanning through listings and attempting to learn more, I was forced to watch tab after tab of progress bar latency in order to see the menu, the location, the about us etc. That site would have been cheaper to upgrade by anybody, rank higher on search engines, load faster and create less frustrated visitors. The KISS principle does apply. The pictures were beautiful; the layout was very appealing, the information organized – but the experience utterly annoying. Is that the best impression the business owner could impart on a potential customers?
In another instance, I was searching for a specialty product, and found it about 40 miles away. After having spent the time driving there and making a purchase, I discovered a location much closer to my house. What made the different? The far store had a website with full online catalog in HTML. The close by store had a flash only site. Snazzy – but missed a sale.
I have been to some sites that make great use of Flash though, and it would be foolish to discount the technology for its potential pitfalls. On the contrary – its adoption and application should be studied and considered when new design projects com up. There are many sites containing laundry lists of good vs. bad design. This article is no such list. But when is Flash well suited?
- Where a custom tool is created for order processing. Photo order sites, custom printing, fashion model virtualization etc. In these cases Flash serves an interactive function and is typically not the whole site.
- Where little textual information is required. Walkthroughs, product 360 views, design concept sites targeting highly interested viewers who don't mind waiting for content and where alternative information sources are not available.
- For isolated rich interaction: Games, presentations and doodads that keep the visitor happy watching and engaged – as a single section of the site.
- Offline (DVD, CD) or downloadable media presentations, manuals etc.
- Anywhere that you can do a better job at winning the mind of the visitor without losing another 3 along the way.
Bottom line – use it wisely. If you suspect that any of the problems mentioned above might harm your online business, consider alternatives. And yes, by all means – do use a flash player to play video clips on the net. It is very well suited for that.
d32e15cd-40e0-42ba-bbc4-6ad3383c24bf|0|.0
Categories: General
Posted by
nurih on
1/16/2009 10:25 PM |
Comments (0)
It's that time of year again - Code Camp is next week, hosted at Cal State Fullerton.
Many good presenters, many good sessions.
Show up for one day both two, it's free to attend!
Check it out, come by
26203733-4bd8-43be-81ff-81b37d90a617|0|.0
If you ask the average developer what might be done to improve code, they would probably come up with "use design patterns" or "do code reviews" or even "write unit tests". While all these are valid and useful, it is rare to hear "measure it". It's odd, when you think about it, because most of us consider ourselves scientists or sorts. Some of use obtained a degree in computer science, and we view the coding practice and a deterministic endeavor. Why is it then that we don't measure our work using standard methodologies and objective tools and evidence?
For one, some of us are blissfully unaware of the existence of such methods. Indeed, the science of quality measurement of code has been the domain of university halls more so than practiced in the "real" world. Six Sigma and CMMI are probably the more familiar endeavors prescribing some sort of measure/improve into the coding practice but both include scant little in terms of measuring code itself. Rather they focus on the results of the software endeavor not on the "internal quality" of code.
Another reason for low adoption of code quality measurement is lack of tools. We have wealth of guidance instruments, but less so code quality focused. For example, FxCop and the addition of Code Analysis to VSTS have brought huge contribution to code reviewing and uniformity in coding among teams. But let's face it – with so much guidance, it's all too easy to either dismiss the whole process as "too picky" or focus too much on one aspect of coding style rather than the underlying runtime binary. This is to say that it is very possible that what would be considered "good style" may not yield good runtime, and vice-versa.
For a professional tool which enables you to view, understand, explore, analyze and improve your code look no further than NDepend. (www.ndepend.com). The tool is quite extensive and robust, and has matured in its presentation, exploration and integration capabilities becoming a great value for those of use interested digging deeper then the "my code seems to work" crowd.
The installation is fairly straightforward. You pretty much unpack the download and place your license file in your installation directory. Upon running the tool, you can chose to install integration to VS2005, VS2008 and Reflector (now a RedGate property btw).
Before using the tool for the first time, you can watch a few basic screen casts available from NDepend. The videos have no narration, so I found myself using the pause button if the text balloons flew by a bit quick. But that's no big deal with a 3-5 minute video. Once you get comfortable with the basics, you can almost immediately reap the benefits. Through a very relevant set of canned queries and screens you can quickly get a feel for how your code measures up. A graphic "size gram" presents methods, types, classes, namespaces or assemblies in varying sizes according to measures like lines of code (LOC – either the source itself or the resultant IL), Cyclometric Complexity and other very useful views of code cohesiveness and complexity. This visual let's you quickly identify or drill into the "biggest offender".
Once you chose a target for exploration, the view in the assembly-method tree, the graphic size-gram and the dependency matrix all work in tandem: you chose an element in one, and the focal point shifts or drills down in the other two. There is also a pane which acts like a context menu which displays the metrics numbers for the selected method, field, assembly etc. This allows you to get the summary very quickly at any given point of your exploration.
When you use the dependency matrix, method or types and their dependents are easily correlated. A measure of code quality is how tightly different types are coupled or dependent on each other. Theory is that if a dependency tree is too deep or too vast, change in a type will ripple through a lot of code whereas shallow or narrow dependency will have less dramatically affected by change. So it's a great thing to have a measure of your dependency relationships among your classes and assemblies. This measure tends to affect code most in the maintenance phase, but of course is as useful during initial prototype/refactor cycles pre-release.
Another great feature is a dependency graph, producing a visual map of dependencies among the assemblies analyzed. I have found it very useful when "cold reading" legacy code I was charged in maintaining. Using the visualization I could more quickly determine what's going on and understand how pieces of code work together rather than follow painstakingly with bookmarks and "follow the code" with a debugger.
As for the metrics themselves, you would probably choose your own policy regarding measures and their relevance. For one, the numbers are great as relative comparison of various code pieces. You may find that some dependencies are "very deep" – which in theory is "bad" – but that the indication points to a base class which you designed very well and serves as the base for everything. For an extreme example, most of us will agree that the "deep dependency" on System.String is well justified and doesn't merit change. It is important for the user to understand and digest the metrics in context, and draw appropriate conclusions.
The tool is built on an underlying query technology called CQL. Once a project is analyzed, the database of findings is exposed both through built in queries. These queries can be modified and new queries can be built to correlate your important factors. Quite honestly, I have not gotten to a point of need for customization yet. The existing presentations are very rich and useful out of the box. One instance where you might want to produce custom queries would be to exclude known "violations" by adding a where clause, thereby preventing code you already analyzed and mitigated from appearing or skewing the view of the rest of your code.
In summary, I found NDepend very useful in examining legacy and new code. It gave me insights beyond empirical style oriented rules. It is much more informative to me to have a complexity measure or IL-LOC rather than a rule like "methods should not span more than 2 screen-full". Microsoft does include code metrics in VS 2010, and code analysis in VSTS or testing editions. If that is not within your budget, then you can have NDepend today and gain valuable insight right away. I would advise taking it slow in the beginning because there is a slight learning curve to the tool usage and navigation, and ascribing relevant weight to the findings takes time. But once you get a hang of it, it becomes indispensible.
199ea1fb-2e49-4696-862c-6dcb0772e200|0|.0
Recently I ran into an issue where IIS was refusing to load an otherwise previously perfectly good web application in the solution.
The Visual Studio 2008 solution included a Web Application csproj, and was referencing it by URL on IIS (that is, not a local file based or Cassini web project). Attempting to load the solution brought up an error:
The local IIS URL http://localhost/{YourAppName} specified for Web Project {YourAppName} has not been configured. In order to open this project the Virtual Directory needs to be configured. Would you like to create the Virtual Directory now?
First, checked the IIS manager and ensured application pool and web site were up and operational. All seemingly well.
Since my web application was in fact a WCF web service, I first tried to access the WSDL: It worked. A WSDL was returned, so I knew the web application was operational or at the very least reachable.
Finally I looked more closely at IIS. Clicking the "Web Sites" folder itself brings up a grid on the right. It shows the web site name, port, IP and state. Sorting by [Port], I noticed several web sites were running on 80. The way it works is that one of them had no host headers at all, and the rest had a host header, thereby distinguishing them from the rest of the web sites on the same port.
Normally, I do this when working on several web applications and wanting to mimic production as closely as possible with out the need for multiple IPs on the dev box. At some point, I installed MOSS and used the dev box's WINS name (the name of the machine in AD) as the host header name.
The confusion became clear when looking more closely at the WSDL returned. Although the IP I used was
http://localhost/{MyAppName} , the WSDL link rendered was
http://MyMachineName/{MyAppName}?WSDL ..
This clued in on the answer:
Created a c:\windows\system32\drivers\etc\hosts entry 127.0.0.1 SomeName for the IIS web site which previously was using the machine name as a hosts header, changed IIS so that the host header for the offending site was using the new entry and things are back to normal.
e74883d1-df03-4e6e-82b5-6d0c4288966e|0|.0
We had a practice which included unit testing for a while now, but it entailed Nunit and MBunit with various build frameworks such as CruiseControl and VisualBuilder.
We are running VS2005, and wanted to include running the tests on developer boxes as part of a build, so that failed tests will flunk the build.
Using a post build event, this is easily done:
In the Post Build Events, enter:
CD $(TargetDir)
"$(DevEnvDir)MSTEST.exe" /testcontainer:$(TargetFileName)
The quotes around the MSTEST full path ensure that the space in the name "Program Files" is resolved correctly.
Changing directory to the target directory is easier than setting all explicit paths etc.
This could have been achieved by running a continuous integration server on each machine, but raises the setup complexity.
If MSTEST returns a less than success code, the build will fail.
If you further want to speed development compile/run cycle, you can create a new configuration:
Configuration Manager -> Active Solution Configuration (drop down) <New...> -> name a new debug configuration "Debug No Test"
In the new configuration, check each project in the solution except the test project.
20c3ec10-5c9c-4125-837e-6dc1265d0e48|0|.0