Rockford Lhotka's Blog

Home | Lhotka.net | CSLA .NET

 Monday, July 25, 2016

I have an existing .NET project (CSLA .NET) that uses resx resource files for localization. While adding support to CSLA .NET for .NET Core I had to figure out how to use resx files in a .NET Core (NetStandard 1.5) Class Library.

There is a doc for .NET Core Globalization and Localization that has good info, but it did lead me down a bad road given that I’m bringing in existing code and resx files.

There’s not currently tooling in Visual Studio 2015 for dealing with resources in .NET Core projects, or at least not like you’d expect from VS with full .NET. But there’s enough tooling that if you copy or create a Resources.resx file in a folder of your project you’ll end up with the appropriate generated designer.cs file.

Note that the Microsoft doc says that they think most of us won’t use that generated file. I think they are full of crap, because the alternative is to not use strongly typed access to your resources, and to manually craft a class to access your resources. WTF!?! So I’m ignoring their non-recommendation/supposition that I think is completely wrong, and I’m continuing to rely on the designer.cs file that has provided so much value since 2002.

The problem I encountered is that in the Microsoft doc they talk about putting your resx file(s) into a Resources folder. DO NOT DO THIS.

The tooling that generates the designer.cs file uses the folder name to create the namespace for the generated code. If you use a Resources folder the resulting name (for me) was Csla.Resources. And the class they generate is named Resources. So you have a class named ‘Csla.Resources.Resources’ – and it is a static class. As a result you basically can’t access any of the properties or methods in the class without using the full type name (no using statements allowed)!! It is a total mess.

SO DO NOT NAME YOUR FOLDER ‘Resources’!!

A related problem flows from the fact that I’m using existing code, all of which assumes the resx files are in the ‘Properties’ folder, so the namespace is ‘Csla.Properties’. So really what I need is to have all my resx files in the ‘Properties’ folder within my project so the full type name of the generated code is ‘Csla.Properties.Resources’ just like it has been in .NET projects for years and years and years.

The resx code generation tool appears to only run if the Resources.resx file is really in that folder (not linked from elsewhere), so I needed a way to copy my resx file from its original location into my NetStandard project.json:

"scripts": {     "precompile": "copyResources.cmd"
},

And of course this means that I also have that cmd file in my project’s root folder (a peer with project.json):

del Properties\*.resx
copy ..\Csla.Shared.Resources\*.resx Properties\

Notice how I’m deleting and recopying the files on every build. This is because the master source for my resx files is in the ‘Csla.Shared.Resources’ folder, and I don’t want anyone thinking they can edit the resx file in this copy – that’d be a maintenance issue! (as an aside, I also added these copied resx files to my .gitignore file so they never get checked into source control – they are just a build artifact after all)

As soon as the Resources.resx file is copied into the folder the designer.cs file is created, which means all my code that has ‘using Csla.Properties;’ and that uses the strongly typed members from the ‘Resources’ class will all work.

However, it is also critical that the resx files be leveraged as embedded resources when the project builds. To make this happen I had to add more lines to the project.json file:

"buildOptions": {     "compile": [ "../Csla.Shared/**/*.cs" ],
    "embed": {         "include": [ "Properties/Resources.resx" ]     },
    "define": [ "NETFX_CORE", "NETCORE", "NETSTANDARD" ],     "outputName": "Csla",     "xmlDoc": true
},

The “embed” build option indicates that the Resources.resx file should be embedded as a resource in the compiled DLL from the project. All the other localized resx files are automatically picked up and used to create satellite assemblies just like in full .NET. The result is that my build output directory contains ‘Csla.dll’ with the default resources embedded, and satellite assemblies in per-culture folders as you’d expect.

snip_20160725134541

To summarize:

  1. Do not put your Resources.resx file into a Resources folder – that way lies madness
  2. If porting existing code to .NET Core you’ll almost certainly want to put the resx files into your ‘Properties’ folder to get the same namespace as full .NET
  3. If porting existing code, use a precompile directive to copy the resource files to the target location
  4. Use the “embed” build option to embed your Resources.resx file into your assembly to make the default culture available
Monday, July 25, 2016 12:48:20 PM (Central Standard Time, UTC-06:00)  #    Disclaimer
 Friday, July 22, 2016

I am thrilled with the “Your Groove” functionality in the Groove music app.

Years ago I begged and pleaded to get Pandora-like functionality in the (then) Zune app. Microsoft responded with SmartDJ, which later became Radio – and that has been excellent all these years – and I still use that functionality a lot.

However, this new “My Groove” feature adds a new dimension to the overall experience that I really like a lot. For example:

msohtmlclipclip_image001

The Radio feature sometimes provides new music, but dynamic channels like this one provide a lot of new music. And they auto-update weekly, so they never get stale.

I’m at the point where I think I’ll cancel my SiriusXM subscription in my car, because I can just sync these playlists to my phone and play them via BlueTooth – who needs SXM Octane to find new music when Groove does a better job for a lot less money!

Friday, July 22, 2016 1:22:53 PM (Central Standard Time, UTC-06:00)  #    Disclaimer
 Saturday, June 11, 2016

RDSPK20Now is the time to register for Visual Studio Live! Redmond 2016. Sure, the conference isn’t until early August, but now is the time to get early discounts and all that stuff.

This link gets you one of those discounts: RDSPK20_Reg

This is a great event, right there on the Microsoft campus – often the best of our events in terms of spontaneous opportunities to interact with your favorite Microsoft engineers – and as is the case with all the VS Live events this is the best opportunity to learn about current and future technologies around Microsoft, the web, and mobile app development.

After all my recent health issues, I’m finally back to doing a workshop. Jason Bock and I will be giving a pre-con on distributed computing, including the use of various Azure features, microservices, and of course a little bit of CSLA .NET Smile

I hope to see you there!

Saturday, June 11, 2016 3:38:10 PM (Central Standard Time, UTC-06:00)  #    Disclaimer

Tomorrow I fly to Boston for Visual Studio Live! Boston 2016. If you are attending I look forward to seeing you during the week, it should be a great event!BOSPK17

Saturday, June 11, 2016 3:30:23 PM (Central Standard Time, UTC-06:00)  #    Disclaimer
 Tuesday, June 07, 2016

A very common scenario for line of business apps is to edit a collthIDVUDFR8ection of items. Often this isn’t a bit collection, just a variable number of rows with a few columns to edit per row.

The MVC scaffolding supports this scenario by making it easy to create a set of pages – display the list, create a new item, edit an existing item, confirm removal of an item. And this scaffolding is quite useful, especially for scenarios where each row of data has a lot of properties to edit.

Where it isn’t so useful is in another common case, where each row of data has a small number of properties to edit (and where there are a relatively small number of rows). In this case most users would prefer to just edit all the values on a single screen, not having to navigate to the create/edit/delete pages for each row, as that is quite awkward.

What I’ve found is that there are some (ok, lots) of blog posts and code snippets showing ways to solve this problem. Much of this content dates back many years, often to MVC 2, and shows what (in my view) are some pretty hacky solutions involving client-side JavaScript that manually creates html strings that replicate (often outdated) html comparable to that generated by MVC in Razor. Other solutions use WebGrid, a seemingly little-used feature of MVC that also needs some (less hacky) JavaScript to support editing.

For my purposes, I wanted something simpler, more direct. I don’t mind some postbacks – you’d get those with the standard MVC scaffolding – I just want the user to feel like they are just editing the list of items without a lot of page navigation. Something like this:

snip_20160607190309

I also don’t mind using Session in this case, because I’m building something that will, at most, be used by 0.3% of our employee base, which is currently around 600 people. If we grow enough that scaling is an issue we’ll obviously have

To that end I created a new ASP.NET MVC 5 project in Visual Studio 2015 and added the files in this gist that contain the implementation.

The ProjectListController serves up the initial page, and accepts POST operations from the browser.

The Index method displays the page with the collection data. If Session is empty the data is loaded from the database, otherwise the cached Session data is used to populate the page. Typically this means that the first time the user arrives at the page they’ll get fresh data from the database, and on postback operations the data will come from Session. Basically I’m using Session as an in-memory scratch location for the data until all edits are complete and the user clicks the button to save the data.

The POST method works differently depending on the button clicked by the user, handling add, remove, cancel, and submit operations. The operation is indicated by the value of the button, which flows into the controller through a method parameter. In every case the POST method has the full contents of the collection from the UI that flows from the browser into the method.

The add operation adds a new/empty item to the collection, updates the state in Session and allows the page to be redisplayed. This means the newly added item appears to the user, but hasn’t been saved to the database.

The remove operation removes the selected item or items from the collection, updates the state in Session and allows the page to be redisplayed. This means the removed items are no longer displayed, but haven’t been removed from the database.

The cancel/refresh operation clears Session and redisplays the page, causing the page to display fresh data from the database.

The submit operation saves the data into the database, then clears Session to ensure that when the page is redisplayed that the user gets fresh data from the database (including the newly saved changes).

The Index.cshtml view implements the page, relying on the Person.cshtml view to display each row of data from the collection. The Index view has all the buttons the user can click to trigger the postback operations to the controller as I just described.

The Person.cshtml view creates the edit controls for the properties the user should view/edit for each row.

The Person.cs file implements the model – really the viewmodel. Notice that it has a Removed property which is very UI specific, so this clearly isn’t the actual model you’d ever get/save in a database.

The controller has TODO comments indicating where code should go to invoke the data access layer to retrieve and update the database based on the in-memory collection of Person objects.

Tuesday, June 07, 2016 6:03:58 PM (Central Standard Time, UTC-06:00)  #    Disclaimer
 Wednesday, June 01, 2016

csla win8_fullThis release of CSLA .NET is focused primarily on enhancing the existing Xamarin support. There is now a Csla.dll targeting PCL Profile111, which is the current profile for Xamarin.Forms projects and .NET Core.

There is also now a CSLA-Xamarin NuGet package that includes a Csla.Xaml.dll with support for Xamarin.Forms. This includes the same viewmodel base classes as the other XAML platforms, and an implementation of the PropertyInfo control tailored for use in Xamarin.Forms.

@JasonBock added even more analyzers for Visual Studio 2015 to help developers avoid common coding mistakes when building CSLA .NET business classes.

We now have support for the prerelease of Entity Framework 7.

The pt and pt-BR resources for Csla.dll have been updated. Other languages need updates as well - please contribute if you are a native speaker!

There is a new way to customize the server-side data portal by implementing an interceptor that is invoked via the new DataPortalBroker. (#564)

Full details: https://github.com/MarimerLLC/csla/releases/tag/v4.6.400

The assemblies and packages are all available via NuGet.

Wednesday, June 01, 2016 9:33:18 AM (Central Standard Time, UTC-06:00)  #    Disclaimer
 Thursday, May 26, 2016

th7JTBT6D7There is now a Csla.Xaml.PropertyInfo control for Xamarin Forms as well as WPF/UWP, so you can use the same technique to access all metastate about each property from your XAML.

This means that (now on Xamarin too) you can bind to the property value, as well as CanRead, CanWrite, IsValid, IsBusy, and various other metastate values.

Using this capability your XAML UI can provide the user with immediate and rich visual cues as to whether the user is allowed to read or write the property value, and whether the current property value is valid (and if not, why), as well as whether the property has any outstanding async business rules currently executing.

In short, all the goodness that WPF/Silverlight/UWP developers have enjoyed over the past many years is now available on Xamarin!

(or will be once CSLA .NET 4.6.400 releases in about a week – though you can try it now with the 4.6.400 prerelease available via NuGet)

Thursday, May 26, 2016 3:57:07 PM (Central Standard Time, UTC-06:00)  #    Disclaimer
 Wednesday, May 25, 2016

The CSLA PCL that supports Xamarin includes an implementation of System.ComponentModel.DataAnnotations, and that includes numerous types, one of which is DisplayAttribute.

The PCL uses type forwarding so at runtime the platform's DataAnnotations implementation is used (if available), and the CSLA implementation is only used at runtime for platforms where there's not already an implementation (WinRT Phone is the only remaining platform afaik).

There is a problem with Xamarin however, where all types seem to forward and work fine except for DisplayAttribute. The problem in this case is that at runtime it seems that mono is unable to locate the correct ctor for the type:

"System.MissingMethodException: Method 'DisplayAttribute..ctor' not found.\n  at (wrapper managed-to-native) System.MonoCustomAttrs:GetCustomAttributesInternal (System.Reflection.ICustomAttributeProvider,System.Type,bool)\n  at System.MonoCustomAttrs.GetCustomAttributesBase (ICustomAttributeProvider obj, System.Type attributeType, Boolean inheritedOnly) [0x00019] in /Users/builder/data/lanes/3236/ee215fc9/source/mono/mcs/class/corlib/System/MonoCustomAttrs.cs:128 \n  at System.MonoCustomAttrs.GetCustomAttributes (ICustomAttributeProvider obj, System.Type attributeType, Boolean inherit) [0x00040] in /Users/builder/data/lanes/3236/ee215fc9/source/mono/mcs/class/corlib/System/MonoCustomAttrs.cs:158 \n  at System.Reflection.MonoProperty.GetCustomAttributes (System.Type attributeType, Boolean inherit) [0x00000] in /Users/builder/data/lanes/3236/ee215fc9/source/mono/mcs/class/corlib/System.Reflection/MonoProperty.cs:317 \n  at Csla.Core.FieldManager.DefaultPropertyInfoFactory.GetFriendlyNameFromAttributes (System.Ty
pe type, System.String name) [0x00011] in <filename unknown>:0 \n  at Csla.Core.FieldManager.DefaultPropertyInfoFactory.Create[T] (System.Type containingType, System.String name) [0x00000] in <filename unknown>:0 \n  at Csla.ReadOnlyBase`1[T].RegisterProperty[P] (System.Linq.Expressions.Expression`1 propertyLambdaExpression) [0x0001c] in <filename unknown>:0 \n  at ProjectTracker.Library.ProjectInfo..cctor () [0x00000] in G:\\src\\rdl\\csla\\Samples\\ProjectTracker\\ProjectTracker.BusinessLibrary.Shared\\ProjectInfo.cs:10 "

This exception occurs when the consume app attempts to access the DisplayAttribute associated with a property to retrieve values from the attribute. It appears that mono is unable to create an instance of the attribute object because it can't find the ctor. The DisplayAttribute class has only a default ctor, but is typically initialized using named parameters, such as:

[Display(Name = "foo")]

I don't know what kind of ctor mono is looking for when it fails, but it obviously isn't finding the default ctor and then setting the property value, which is what would be the expected behavior.

I’m tracking this issue in the CSLA GitHub repo: https://github.com/MarimerLLC/csla/issues/579

Steps to reproduce issue

The CSLA ProjectTracker reference app in my fork includes a repro of this issue. To see the issue, do the following:

  1. Clone my fork of CSLA from https://github.com/rockfordlhotka/csla.git
  2. Checkout the 505-xamarin branch: https://github.com/rockfordlhotka/csla/tree/505-xamarin
  3. Open the \Samples\ProjectTracker\ProjectTracker.sln solution
  4. Build the solution – it’ll pull down the CSLA .NET framework from NuGet
  5. Set a breakpoint in the XamarinFormsUi.ViewModels.ProjectList class as shown here
    snip_20160525134558
  6. Set the startup app to ProjectTracker.Ui.Xamarin.Droid
  7. Run the app in debug mode (on an emulator or device)
  8. On the first screen click the All Projects button
    snip_20160525134836

That’ll attempt to load the ProjectList page and ProjectList viewmodel. At this point the exception will occur and you’ll end up on the breakpoint because of the failure to create an instance of ProjectInfo, but that fails because mono can’t create an instance of DisplayAttribute (used on some properties in the ProjectInfo class).

Wednesday, May 25, 2016 12:51:26 PM (Central Standard Time, UTC-06:00)  #    Disclaimer
 Friday, May 20, 2016

I might have found a bug in mono, but want to see if anyone thinks I'm missing something.

The CSLA .NET framework has long included an implementation of the System.ComponentModel.DataAnnotations namespace for platforms where Microsoft/Xamarin didn’t provide that functionality. These days I think that is only Windows Phone 8.1, but that includes PCL Profile111 (which is what Xamarin currently targets as well).

Of course the CSLA implementation includes the DisplayAttribute class, which is used to decorate properties in consuming classes like this:

[Display(Name = "blah")]

That "blah" value is a human readable name/label for a property.

Because mono actually provides a System.ComponentModel.DataAnnotations implementation, my PCL uses type forwarding so at runtime the PCL implementation is ignored in favor of the platform-specific implementation provided by mono. For example:

[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))]

This works great on all platforms - except Xamarin Android/iOS where mono throws an exception because it can't find a matching constructor.

The thing is that the DisplayAttribute class has only the default constructor. The syntax being used to set the Name property of the attribute is supposed to use the default ctor, and then the Name property is explicitly set. This is a relatively old feature of C# - but I kind of suspect mono has a bug around this area, as it seems to be looking for a ctor that accepts a parameter when it should use the default ctor.

Friday, May 20, 2016 3:40:28 PM (Central Standard Time, UTC-06:00)  #    Disclaimer
On this page....
Search
Archives
Feed your aggregator (RSS 2.0)
July, 2016 (2)
June, 2016 (4)
May, 2016 (3)
April, 2016 (4)
March, 2016 (1)
February, 2016 (7)
January, 2016 (4)
December, 2015 (4)
November, 2015 (2)
October, 2015 (2)
September, 2015 (3)
August, 2015 (3)
July, 2015 (2)
June, 2015 (2)
May, 2015 (1)
February, 2015 (1)
January, 2015 (1)
October, 2014 (1)
August, 2014 (2)
July, 2014 (3)
June, 2014 (4)
May, 2014 (2)
April, 2014 (6)
March, 2014 (4)
February, 2014 (4)
January, 2014 (2)
December, 2013 (3)
October, 2013 (3)
August, 2013 (5)
July, 2013 (2)
May, 2013 (3)
April, 2013 (2)
March, 2013 (3)
February, 2013 (7)
January, 2013 (4)
December, 2012 (3)
November, 2012 (3)
October, 2012 (7)
September, 2012 (1)
August, 2012 (4)
July, 2012 (3)
June, 2012 (5)
May, 2012 (4)
April, 2012 (6)
March, 2012 (10)
February, 2012 (2)
January, 2012 (2)
December, 2011 (4)
November, 2011 (6)
October, 2011 (14)
September, 2011 (5)
August, 2011 (3)
June, 2011 (2)
May, 2011 (1)
April, 2011 (3)
March, 2011 (6)
February, 2011 (3)
January, 2011 (6)
December, 2010 (3)
November, 2010 (8)
October, 2010 (6)
September, 2010 (6)
August, 2010 (7)
July, 2010 (8)
June, 2010 (6)
May, 2010 (8)
April, 2010 (13)
March, 2010 (7)
February, 2010 (5)
January, 2010 (9)
December, 2009 (6)
November, 2009 (8)
October, 2009 (11)
September, 2009 (5)
August, 2009 (5)
July, 2009 (10)
June, 2009 (5)
May, 2009 (7)
April, 2009 (7)
March, 2009 (11)
February, 2009 (6)
January, 2009 (9)
December, 2008 (5)
November, 2008 (4)
October, 2008 (7)
September, 2008 (8)
August, 2008 (11)
July, 2008 (11)
June, 2008 (10)
May, 2008 (6)
April, 2008 (8)
March, 2008 (9)
February, 2008 (6)
January, 2008 (6)
December, 2007 (6)
November, 2007 (9)
October, 2007 (7)
September, 2007 (5)
August, 2007 (8)
July, 2007 (6)
June, 2007 (8)
May, 2007 (7)
April, 2007 (9)
March, 2007 (8)
February, 2007 (5)
January, 2007 (9)
December, 2006 (4)
November, 2006 (3)
October, 2006 (4)
September, 2006 (9)
August, 2006 (4)
July, 2006 (9)
June, 2006 (4)
May, 2006 (10)
April, 2006 (4)
March, 2006 (11)
February, 2006 (3)
January, 2006 (13)
December, 2005 (6)
November, 2005 (7)
October, 2005 (4)
September, 2005 (9)
August, 2005 (6)
July, 2005 (7)
June, 2005 (5)
May, 2005 (4)
April, 2005 (7)
March, 2005 (16)
February, 2005 (17)
January, 2005 (17)
December, 2004 (13)
November, 2004 (7)
October, 2004 (14)
September, 2004 (11)
August, 2004 (7)
July, 2004 (3)
June, 2004 (6)
May, 2004 (3)
April, 2004 (2)
March, 2004 (1)
February, 2004 (5)
Categories
About

Powered by: newtelligence dasBlog 2.0.7226.0

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2016, Marimer LLC

Send mail to the author(s) E-mail



Sign In