.NET Developer Days in Wroclaw

by Oliver 15. October 2014 19:39

I'm currently attending the first .NET Developer Days conference in Wrocław, Poland, and will put up a few posts with my notes from some of the sessions I was able to attend. The conference took place from 14.10. to 16.10.2014 in the Wrocław Stadium. Here's a list of all posts (I'll update the links as soon as I finish a given post): Visual Studio 2013 Hidden Gems ASP.NET vNEXT SQL Server Data Tools: An Intro Continuous Deployment WebAPI, OData There's already been a lot of input and the third day is still ahead of me! I hope I'll be able to update the above list soon. Happy Coding!

Sample SMTP Session with Auth Login

by Oliver 13. June 2013 15:27

This post is most of all a log drop of an SMTP session I had with our mail server over telnet. We use hMailServer for all of our own and hosted e-mail accounts. Today, I set up a new account to use for our SQL servers to report any problems. I couldn't get SQL Server's DatabaseMail to successfully send any e-mail so I went to find out what might be wrong by myself. Here's my first successful chat with our mail server using AUTH LOGIN, i.e. username and password authentication: 1: 220 mail.teamaton.com ESMTP                                   // started session with: telnet mail.teamaton.com 25 2: hello                                                         // my first try - not quite ;-) 3: 502 Use HELO/EHLO first. 4: HELO                                                          // ok, I got you 5: 501 HELO Invalid domain address. 6: HELO                                                          // say again? 7: 502 Use HELO/EHLO first. 8: EHLO 25.0.153.55                                              // send a host name of the computer you're on 9: 250-mail.teamaton.com 10: 250-SIZE 15000000 11: 250 AUTH LOGIN 12: MAIL FROM: <sql*******@teamaton.com>                          // the from address to use for the e-mail 13: 250 OK 14: RCPT TO: <oliver*******@******.com> // trying to set a recipient's address 15: 530 SMTP authentication is required. 16: AUTH LOGIN                                                    // initiating login 17: 334 VXNlcm5hbWU6                                              // the server is asking for my username in base64 encoding 18: c3FsLXNl***************vbi5jb20=                              // sending my username in base64 encoding 19: 334 UGFzc3dvcmQ6                                              // the server is asking for my password in base64 encoding 20: YkZwN***************A1dng=                                    // sending my password in base64 encoding 21: 535 Authentication failed. Restarting authentication process. // oops, I copied some invisible character from that encoding web page 22: auth login                                                    // try again 23: 502 Unimplemented command.                                    // case seems to matter 24: AUTH LOGIN 25: 334 VXNlcm5hbWU6 26: c3FsLXNl***************vbi5jb20= 27: 334 UGFzc3dvcmQ6 28: YkZwN***************A1dng= 29: 235 authenticated.                                            // finally! 30: DATA                                                          // set the body of the e-mail 31: 503 Must have sender and recipient first.                     // hm, I thought I set the sender already… 32: MAIL FROM: <sql*******@teamaton.com>                          // oh well, set it again 33: 503 Issue a reset if you want to start over                   // I didn't want to start over! 34: RCPT TO: <oliver*******@******.com>                           // set only the missing recipient, then 35: 250 OK 36: DATA                                                          // now, set the mail body 37: 354 OK, send. 38: Test mail here. 39:  40: .                                                             // mark the end of the mail body 41: 250 Queued (11.247 seconds) 42: 421 Connection timeout.                                       // that's what happened after a while when I left the shell open 43:  44: Connection to host lost. 45:  46: C:\Users\Oliver> Every line that starts with a status code was sent by the server, the rest of them is what I entered. Just for the record.

ToDebugString() – give me some debug info about my object, e.g. Request.Url

by Oliver 16. September 2011 20:06

Lately, I was having trouble debugging certain parts of my code in Visual Studio, and all I wanted to know was the value of some variable at some point in time. Well, I’d use some logging if I could just get at that value easily. But for some objects I don’t really know what I’m looking for or where I should be looking for it. So just give me the values of all the members of that object, will ya? And could you recurse that? But no deeper than 3 levels, alright? Or let’s say… 5? public static string ToDebugString(this object obj, int maxdepth, int depth=0) { if (obj == null) return "null";   if (obj is IConvertible) return obj.ToString();   if (depth >= maxdepth) return "...";   var sb = new StringBuilder();   if (depth > 0) sb.AppendLine();   foreach (var propertyInfo in obj.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance)) { sb.Append(new string(' ', 2*depth)).Append(propertyInfo.Name).Append(": "); try { var value = propertyInfo.GetValue(obj, new object[0]); sb.AppendLine(ToDebugString(value, maxdepth, depth + 1)); } catch (Exception ex) { sb.AppendLine(string.Format("[{0}]", ex.Message)); } }   // remove newline from end of string var newLine = Environment.NewLine; if (sb.Length >= newLine.Length) sb.Replace(newLine, "", sb.Length - newLine.Length, newLine.Length);   return sb.ToString(); } With this little helper I can now simply call anyobject.ToDebugString(4 /* maxdepth */) and I get a nicely formatted debug view of that object; e.g. Request.Url.ToDebugString(3) gives me: AbsolutePath: /logg.aspxAbsoluteUri: http://localhost:55235/logg.aspxAuthority: localhost:55235Host: localhostHostNameType: DnsIsDefaultPort: FalseIsFile: FalseIsLoopback: TrueIsUnc: FalseLocalPath: /logg.aspxPathAndQuery: /logg.aspxPort: 55235Query: Fragment: Scheme: httpOriginalString: http://localhost:55235/logg.aspxDnsSafeHost: localhostIsAbsoluteUri: TrueSegments: Length: 2 LongLength: 2 Rank: 1 SyncRoot: Length: 2 LongLength: 2 Rank: 1 SyncRoot: ... IsReadOnly: False IsFixedSize: True IsSynchronized: False IsReadOnly: False IsFixedSize: True IsSynchronized: FalseUserEscaped: FalseUserInfo: Nice Right now this method chokes on indexed properties but once I’ll need it I’ll go and look for a way to include them. It also chokes any exceptions on the way to just get the job done. Happy coding!

Unexpected EOF encountered in BCP data-file

by Oliver 15. September 2011 17:05

Today, I tried importing a CSV file like the following into one of our MS SQL Server databases: Id;Latitude;Longitude 4610;43.7119;-1.0737 5502;49.4297;-1.806 11360;46.9343;-1.8875 I tried it using the following command line: 1: bcp GeoDataImport in geodata.csv -w -t; -T but that threw the mentioned error: “Unexpected EOF encountered in BCP data-file” cmd> bcp GeoDataImport in geodata.csv -w -t; -TStarting copy... SQLState = S1000, NativeError = 0 Error = [Microsoft][SQL Server Native Client 10.0]Unexpected EOF encountered in BCP data-file 0 rows copied. Network packet size (bytes): 4096 Clock Time (ms.) Total : 1 I’ve had this problem before and somehow managed to remember that it might have something to do with the encoding of the file. So I opened it with Notepad++ where you can easily check and change the file encoding and found it was ANSI encoded: Well, the UCS-2 Little Endian encoding is what SQL Server expects as default encoding, so I changed the encoding, saved the file and imported it again – with success. UCS-2 might be something you rarely hear about – that’s because it’s been superseded by UTF-16 but in most situations they are pretty much identical (check out http://en.wikipedia.org/wiki/UTF-16/UCS-2 for more info). That’s all for now – happy coding!

Creating a new module in ‘discoverize’ – using multi-file templates and good ol’ batch scripts

by Oliver 15. July 2011 09:07

For our portal software discoverize I was looking for a way to create new modules faster and more reliably. The basic structure would always be the same, so a Visual Studio multi-file template seemed appropriate: Well, unfortunately I didn’t find a way to create new folders with that approach. Multi-file templates really do what they say: they create multiple files from templates. Nothing else. So I put together a short batch script that would create the directory structure needed for any new module: I can quickly open a new command line window by using any one of several Visual Studio extensions (e.g. PowerCommands for Visual Studio 2010): … and simply run: Now going back to Visual Studio we have to include the new Feature folder in the project: Then hit Ctrl + Shift + A to open the Add New Item dialog, select ‘Discoverize Module’ and type Feature in the Name textbox (unfortunately, there seems to be no easy way to automatically put the name of the folder inside that textbox): This step will generate three code files, that are the backbone of every module: FeatureConfig.cs, FeatureModule.cs, and FeatureViews.cs. Finally, our multi-file item template comes into play! Handling the multi-file template The multi-file item template for a new module consists of four files: the template definition file Module.vstemplate and the template code files Config.cs, Module.cs, and Views.cs: Those four files have to be packed into a zip file and copied to a folder underneath %UserProfile%\My Documents\Visual Studio 2010\Templates\ItemTemplates\ – I put this one into Visual C#\Code. That’s how it appeared under the Visual C# –> Code section in the Add New Item dialog. Since it is somewhat cumbersome to zip and copy updated versions of the template (especially during early development where I keep adjusting and tuning the template code), I put together another batch file that does that for me. It basically does three things: Get the name of current folder to use as name for the zip file (found the solution here) Use 7-zip to zip the four files. Copy the zip file to the VS custom template directory. The real script contains some safety nets and more output so that in case it won’t work across all developer machines I can get quick feedback as to what exactly didn’t work instead of just “it didn’t work”. Happy Coding!

Code evolution + LINQ

by Oliver 28. June 2011 01:27

Three year old code: 1: protected string CpeBehaviorIds() 2: { 3: var cpeIds = ""; 4:  5: var helpItems = GetHelpItems(divGlobal); 6:  7: foreach (var helpItem in helpItems) 8: cpeIds += helpItem.CollapsiblePanelBehaviorID + ','; 9:  10: // remove comma at end 11: if (cpeIds.Length > 0) 12: cpeIds = cpeIds.Remove(cpeIds.Length - 1); 13:  14: return cpeIds; 15: } 16:  17: protected string CpeExpandIds() 18: { 19: var cpeIds = ""; 20:  21: var helpItems = GetHelpItems(divGlobal); 22:  23: foreach (var helpItem in helpItems) 24: cpeIds += helpItem.CollapsiblePanelExpandID + ','; 25:  26: // remove comma at end 27: if (cpeIds.Length > 0) 28: cpeIds = cpeIds.Remove(cpeIds.Length - 1); 29:  30: return cpeIds; 31: } 32:  33: protected static List<HelpItem> GetHelpItems(Control control) 34: { 35: var idList = new List<HelpItem>(); 36:  37: if (control is HelpItem) 38: idList.Add(control as HelpItem); 39: else 40: foreach (Control child in control.Controls) 41: idList.AddRange(GetHelpItems(child)); 42:  43: return idList; 44: } New code: 1: protected string CpeBehaviorIds() 2: { 3: return divGlobal.Controls<HelpItem>().Select(h => h.CollapsiblePanelBehaviorID).JoinNonEmpty(","); 4: } 5:  6: protected string CpeExpandIds() 7: { 8: return divGlobal.Controls<HelpItem>().Select(h => h.CollapsiblePanelExpandID).JoinNonEmpty(","); 9: } 10:  11: public static string JoinNonEmpty(this IEnumerable<string> values, string separator) 12: { 13: return String.Join(separator, values.Where(s => !string.IsNullOrEmpty(s)).ToArray()); 14: } LINQ – we love you! Oliver P.S. Controls<Type>() is another extension method defined like this: 1: /// <summary> 2: /// Returns all controls of the given Type that are found inside this control. 3: /// Searches recursively. 4: /// </summary> 5: public static IEnumerable<T> Controls<T>(this Control control) where T : Control 6: { 7: var controls = control.Controls; 8:  9: if (controls.Count == 0) return new List<T>(0); 10:  11: var newColl = new HashedSet<T>(); 12: foreach (Control child in controls) 13: { 14: if (child is T) 15: newColl.Add((T) child); 16:  17: var childColl = child.Controls<T>(); 18: foreach (T ctrl in childColl) 19: newColl.Add(ctrl); 20: } 21:  22: return newColl; 23: }

Gender: Web Developer vs. Web Developer

by andrej 10. March 2011 14:54

Web Developers vs Web Developers from Cassie McDaniel on Vimeo. I love the role the designer plays in this video :) [via graphic.is]

About Oliver

shades-of-orange.com code blog logo I build web applications using ASP.NET and have a passion for javascript. Enjoy MVC 4 and Orchard CMS, and I do TDD whenever I can. I like clean code. Love to spend time with my wife and our children. My profile on Stack Exchange, a network of free, community-driven Q&A sites

About Anton

shades-of-orange.com code blog logo I'm a software developer at teamaton. I code in C# and work with MVC, Orchard, SpecFlow, Coypu and NHibernate. I enjoy beach volleyball, board games and Coke.