čtvrtek 4. července 2013

Search and destroy!

This

in case you would not know is the search ... erm ... thing ... in Visual Studio 2012. I would not call that dialog, something so outdated could not be used in the new, carefully designed, incredible, ubercool and megalovely formerly-known-as-Metro-but-the-Metro-company-rightfully-complained style. So let's call that a "thing". Now quick! is the search gonna be case sensitive or case insensitive? Is it gonna be whole word only or not? Is it gonna use "regular expressions" or not (I wonder do they still use their own braindead something that kinda resembles incorrectly understood and mostly forgotten regexps or actual ones)?


Dear designer, it's commendable that you try to save space. You did a very bad job on this "thing" though. The whole team that designed the new version of Visual Studio should be fired and never ever let anywhere near computers again! Ever!


I pity all those that worked hard on the additions to the language, improvements of the compiler and tools that their work is hidden under the heap of crap that is the new UI!

úterý 6. března 2012

blah.blih(bla,bla,bla).Whatever.Substring(0,6) kabooom

Yes you are right, this is yet another of the "someone's stupid" posts. Is there anyone, anyone at all, who thinks it's a good idea to throw an ArgumentOutOfRangeException("Index and length must refer to a location within the string.") if the second parameter to Substring() is too big? For gawds sake when was there a time you cared? I want the bloody result to be at most 6 fscking characters! I don't give a flying fsck if it's four already! No body gives a flying fuck! It might make sense to throw when the index points outside the string even though a more sensible approach would be to stay calm and return an empty string, but throwing just because there's not enough silly characters is simply ... microsoftish.

čtvrtek 4. srpna 2011

enumerable.Distinct(IEqualityComparer what???

Now I understand years ago when there were no lambdas in C# and the syntax for function references (delegates for the C# folk) was so convoluted that they were almost unusable ... at those dark times all those IEqualityComparers and loads of other interfaces made some sense but now? All I want is to filter some enumerable to get only the distinct values where distinct means the .ArticleId property is different (other properties either depend on ArticleId or are irrelevant and will not be used when processing the filtered list). Should be simple right? I expected something like var filtered = list.Distinct( (obj1, obj2) => obj1.ArticleId == obj2.ArticleId ); or even (as the ArticleId is a plain old int) var filtered = list.Distinct( obj => obj.ArticleId ); Too simple. ... private class DogsWithTheSameArticle : IEqualityComparer<WatchDogsToSend> { public bool Equals(WatchDogsToSend dog1, WatchDogsToSend dog2) { return dog1.ArticleId == dog2.ArticleId; } public int GetHashCode(WatchDogsToSend dog) { return dog.GetHashCode(); } } ... ... many a line away ... ... var filtered = notification.Distinct((IEqualityComparer<WatchDogsToSend>)(new DogsWithTheSameArticle())); OK. It works. But it's long and ugly, ugly, ugly. Let us hide the insanity! private class LambdaEqualityComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _comparer; public LambdaEqualityComparer(Func<T, T, bool> comparer) { _comparer = comparer; } public bool Equals(T obj1, T obj2) { return _comparer(obj1, obj2); } public int GetHashCode(T obj) { return 0; } } private class LambdaEqualityComparer<T,M> : IEqualityComparer<T> { private Func<T, T, bool> _comparer; private Func<T, M> _selector; public LambdaEqualityComparer(Func<T, M> selector) { _selector = selector; _comparer = (obj1, obj2) => Object.ReferenceEquals(obj1, obj2) || obj1 != null && obj2 != null && selector(obj1).Equals(selector(obj2)); } public bool Equals(T obj1, T obj2) { return _comparer(obj1, obj2); } public int GetHashCode(T obj) { return _selector(obj).GetHashCode(); } } /// <summary> /// Filters the enumerable to contain only distinct elements using a custom comparator. /// </summary> /// <param name="comparator">a lambda that returns true if the two objects are to be considered equal</param> public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list, Func<T, T, bool> comparator) { return list.Distinct(new LambdaEqualityComparer<T>(comparator)); } /// <summary> /// Filters the enumerable to contain only distinct elements using a custom comparator. /// </summary> /// <param name="comparator">a lambda that extracts the value(s) to compare. If the selected values are equal, the objects are considered duplicate</param> public static IEnumerable<T> Distinct<T, TElem>(this IEnumerable<T> list, Func<T, TElem> selector) where TElem : IComparable { return list.Distinct(new LambdaEqualityComparer<T, TElem>(selector)); }

čtvrtek 21. července 2011

System.Web.Mvc.UpdateModel() throws exceptions after succeeding to update an object

Yes, the message is right. Even though the docs claim that it throws "System.InvalidOperationException: The model was not successfully updated."

The catch is that it throws the exception even if the model was successfully updated. Even if there was nothing to update at all. Even if there is a custom model binder for the type of the object you are trying to update, you step through the code and everything in the update works fine, all the properties are updated as they should, everything validates, the last line of your code returns exactly what it should and then KABOOOOM.

The model of type 'XXXXXX' could not be updated

Luckily in this particular case the source code is available so after some time with the sources of ASP.Net MVC you can find the reason. The (censored) who wrote the code decided to throw the exception whenever there is an error in the ModelState dictionary after updating the model. Sounds right, or not? Wait! What if there was something already before the UpdateModel() call? What if some other model failed, was handled and now I need to import some of the data into another object ... no way, as soon as there's an error, you get an exception. Your error, his error, their error, who the heck cares. Kabooom. Hooooray, we have an excuse to throw an exception!


Now if you don't really mind whether the update worked or not you can just use TryUpdateModel() and ignore the incorrect result. If you do care ... good luck.

čtvrtek 14. července 2011

MSSQL and WEEKDAY

OK. So you can set which day of the week is the "first" and then the DATEPART(weekday,@date) returns a number from 1 to 7 with the specified day being "1". The documentation is rather convoluted, but well ... what would you expect. So everything is nice and dandy isn't it?

No it is not. The catch is that the SET DATEFIRST is not stored with the stored procedure or function, but rather taken from the current connection. So you write for example a function that returns the first Monday at least N days after a specified date and ... pray that someone for whatever reason doesn't set DATEFIRST to anything else than it was set to when you tested the function. Cause the function doesn't remember what it was set to when it was parsed, you can't set it from within the function and there is no way to pass that option to DATEPART() explicitely.

Now that's what I call a stupid interface.


CREATE FUNCTION dbo.GetWeekDay(@Date datetime) RETURNS int
AS
BEGIN
Declare @day int
set @day = 1 + ((@@DATEFIRST + DATEPART( weekday, @Date) - 2) % 7);
return @day
END
go

At last something that's consistent. Agrrrrrr.

pondělí 13. června 2011

Trailing slash in URLs

We are working on an eShop using ASP.Net MVC. The client wanted the URLs to look nice ... no big deal, URLs look nice in MVC, blah.com/detail/15, blah.com/category/45, ...
Not nice enough. We want the name of the article/category in the URL like this: blah.com/15/of_mice_and_men
OK, we are generating all URLs using MVC Futures so there's always some Html.Link("blah", MVC.Detail.Index(Model.ArticleId)) so how can I tweak this to generate that URL?

First thing ... make sure we accept them:

routes.MapRoute(
  "Detail and name",
  "detail/{id}/{name}/",
  new { controller = MVC.Detail.Name, action = MVC.Detail.ActionNames.Index },
  new { id = @"^\d+$" } 
);

next we need to add the name to the RouteDataDictionary somehow. We could add the name as a parameter to the action (even though it doesn't need it) and call MVC.Detail.Index(Model.ArticleId, Model.ArticleName), but we have that on quite a few places already and we do not always have the name handy. Mkay, let's tweak some .tt In this case the T4MVC.tt. And let's do it in a gerenal way ... whenever there is a protected method RenderLink_<ActionName> in the controller, let's call it from the generated pseudoaction in the T4MVC_<ControlerName>Controller in the <ControllerName>Controller.generated.cs and let it tweak the RouteValueDictionary as needed.
Then all that is left is adding


protected void RenderLink_Index(T4MVC_ActionResult callInfo) {
  if (callInfo.RouteValueDictionary.ContainsKey("id") && callInfo.RouteValueDictionary["id"is int) {
   callInfo.AddRouteValue("name"Article.TitleForId((int)callInfo.RouteValueDictionary["id"]).EscapeForNiceUrl());
  }
 }

into the controller and all URLs to details look as requested.

Until they come again that they want a slash at the end of the URL. OK, fine, but how? Including or not the slash in the MapRoute makes no difference. OK, the route object has some GetVirtualPath, is this what I need? I could let the inherited implementation to generate the URL and then append or insert (remember, there may be a query or hash in the URL!) the slash.

Now let's add (copy&paste&tweak) the extension methods to simplify adding the routes


public static class RouteCollectionExtensions {
  public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url) {
   return MapRouteWithSlash(routes, name, url, null /* defaults */, (object)null /* constraints */);
  }
 
  public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults) {
   return MapRouteWithSlash(routes, name, url, defaults, (object)null /* constraints */);
  }
 
  public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults, object constraints) {
   return MapRouteWithSlash(routes, name, url, defaults, constraints, null /* namespaces */);
  }
 
  public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, string[] namespaces) {
   return MapRouteWithSlash(routes, name, url, null /* defaults */null /* constraints */, namespaces);
  }
 
  public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults, string[] namespaces) {
   return MapRouteWithSlash(routes, name, url, defaults, null /* constraints */, namespaces);
  }
 
  public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
   if (routes == null) {
    throw new ArgumentNullException("routes");
   }
   if (url == null) {
    throw new ArgumentNullException("url");
   }
 
   Route route = new RouteWithSlash(url, new System.Web.Mvc.MvcRouteHandler()) {
    Defaults = new RouteValueDictionary(defaults),
    Constraints = new RouteValueDictionary(constraints),
    DataTokens = new RouteValueDictionary()
   };
 
   if ((namespaces != null) && (namespaces.Length > 0)) {
    route.DataTokens["Namespaces"] = namespaces;
   }
 
   routes.Add(name, route);
 
   return route;
  }
 
 }

and

routes.MapRouteWithSlash(
  "Detail and name",
  "detail/{id}/{name}/",
  new { controller = MVC.Detail.Name, action = MVC.Detail.ActionNames.Index },
  new { id = @"^\d+$" }
 );


and we have the slash :-)

pondělí 4. dubna 2011

cannot derive from sealed type 'System.ComponentModel.EditorAttribute'

Yep, lovely. Yet another sealed class. Why?!?

OK, so I wrote a Visual Studio plugin that extends the Entity Framework designer. Everything's working fine. Well ... mostly ... the fact that if and only if there is a plugin, any validation problems in the updated .edmx are fatal and attributed to the plugin without the user having any chance to fix the problems ... in 99.784% of cases caused by the original code ... yeah, that's pretty annoying ... the only solution is to write a copy of the .edmx into a different file just before the EF Designer starts the validation and then replace the .edmx by this copy and fix the huge "Hey, I don't know what's the primary key for this view" problem.

Anyway ... most of the attributes I need to add to the properties that I want to display in the EF Designer are kinda OK. [DisplayName("...")], ["Description("...")], [Category("..")], [DefaultValue(...)]. All that's OK.

If I want a dropdown I just define an enum and it works automatically. (And if I want a dropdown with a dynamic list of options it ... well ... I haven't found a way to do that).

Then if I want a multiline input for the property, I know how to do it, it's just an attribute. An attribute that looks like this:

[EditorAttribute(typeof(System.ComponentModel.Design.MultilineStringEditor), 
 typeof(System.Drawing.Design.UITypeEditor))]

Lovely, isn't it?

OK, so I thought I could define subclass (named for example MultiLineAttribute) that'd use the inherited constructor with those values:


public class MultiLineAttribute : System.ComponentModel.EditorAttribute {
  public MultiLineAttribute()
   : base(typeof(System.ComponentModel.Design.MultilineStringEditor),
    typeof(System.Drawing.Design.UITypeEditor)) { }
 }
Nope. Cannot derive from sealed type.

Why?!? Why the heck does the silly class have to be seaeaeaeaealed?