FroshKiller All American 51913 Posts user info edit post |
I'm developing for an ASP.NET application. It targets the .NET 4.0 runtime. For reasons, we aren't using ASP.NET MVC. Here is a common use pattern:
1. Render a form with fields for selecting bits of data you're interested in. 2. The user makes selections on the form and posts it back to the server. 3. The application server maps the form selections to the conditions of a database query. 4. The record set returned by the query is bound to a table in the HTML response.
What I'm trying to do is move the application toward using classes that manage two key pieces: displaying an appropriate form and displaying an appropriate table. What I'd like to do is use attributes to mark specific members of a class as eligible for use in those contexts.
I know that inspecting attributes at runtime is icky. I don't care. We're using reflection all over the place, so who gives a shit? Literally no one will notice or care.
Here is an example I have in mind. Let's say I have a screen for looking up widgets. I want to define a Widget class that handles reading widget records from the database and all that jazz. A Widget's properties might include ProductType, ModelNumber, Price, IsSecretlyABomb, and IsDiscontinued.
ProductType and IsDiscontinued would be useful things to have on the form used to filter the lookup. Everything except IsSecretlyABomb is a good candidate to include in the tabular results.
I'd like to define attributes like maybe <Filterable("Multiple")> on the ProductType property, for example. Then, I could have one well designed and well implemented form manager sort of class that can take the Widget class, see which members are flagged with the appropriate attributes, and dynamically access those for form rendering so I'll never have to write any of this stupid boilerplate again.
I hesitate because it feels like I'm forgetting a better option. I can't really refactor any existing classes to make them conform to new interfaces or inherit from a different base class, but adding custom attributes for this seems like a slam dunk to me. Thoughts? 12/7/2015 1:55:37 PM |
Novicane All American 15416 Posts user info edit post |
php that way ->>> 12/7/2015 6:33:25 PM |
qntmfred retired 40807 Posts user info edit post |
if you can bind your forms to a dynamic you could do this
public static dynamic ToDynamic(this object value) { IDictionary expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) { if (property.Attributes.OfType<IsFilterableAttribute>().Any()) { expando.Add(property.Name, property.GetValue(value)); } }
return expando as ExpandoObject; }
that'll return a type that just has the properties on it you care about.]12/8/2015 12:21:54 AM |
moron All American 34183 Posts user info edit post |
Wouldn't you want this to be controllable by the user, rather than be in the code? Seems like this info should be in a database or config file somewhere, not part of a class... 12/8/2015 2:22:50 AM |
FroshKiller All American 51913 Posts user info edit post |
qntmfred said:
Quote : | "if you can bind your forms to a dynamic you could do this" |
You're just offering that up as a sample naive implementation of how to actually get the filterable properties once I've gone ahead with my idea, right? That looks useful.
moron said:
Quote : | "Wouldn't you want this to be controllable by the user, rather than be in the code? Seems like this info should be in a database or config file somewhere, not part of a class..." |
Nah. That'd open me up to users making bad choices, thus diminishing the value of what they're seeing on screen. Users are like, "Show me everything!" Well, "everything" includes a load of misleading and confusing data, dude. Good specs mean you're seeing everything you need to see to make an informed decision and not one datum more.
Plus that would drastically increase the amount of code/scripts/whatever additional resources that'd need maintaining. If I get hit by a bus and the next guy wants to add some date property to the output, he has to remember, "Oh yeah, I have to add a new line to the PROPERTIES MANIFEST CONFIG FILE," etc.
I'm sure someone else will have the bright idea to add a GetFilterableProperties function or something that returns an array of property names or something like that. That's cute, but it would involve making broad changes with compile-time consequences. Yeah, adding attributes technically means those things as well, except we don't have the overhead of an additional function defined for every supported class. We're running in Object Explorer stealth mode here. The anatomies of the classes don't change with new attributes.12/8/2015 6:38:46 AM |
aaronburro Sup, B 53137 Posts user info edit post |
For the love of all that is holy, please don't use a fucking ExpandoObject. I'm saying this for the person who comes after you. Please. Don't do it. 12/11/2015 12:09:38 AM |
FroshKiller All American 51913 Posts user info edit post |
Okay, but why not? 12/11/2015 7:52:36 AM |
Wolfmarsh What? 5975 Posts user info edit post |
I'd like to know why too. ExpandoObjects are really useful in certain scenarios, like reading JSON or YAML that you don't have the corresponding class definition for. 12/11/2015 8:37:43 AM |
aaronburro Sup, B 53137 Posts user info edit post |
Because it's not one of ^ scenarios. You have a strongly typed object already. It is an enormous pain to debug code with ExpandoObjects, almost as much as debugging DataTables. It's even harder to deduce what the hell is happening and when it is safe to add/remove properties with them. People just add stuff at random to them, and down the line you are faced with the nightmare of "what does this property actually do again?"
If this is a throwaway app, then do it. If it's not, then find a better solution. I'd go in the direction of creating the table and then dynamically removing columns based on the property attributes. 12/13/2015 7:05:33 PM |
AntecK7 All American 7755 Posts user info edit post |
Does the user really need that much customization for the table render? What type of interaction does the user need to perform with the table? Do you need to handle different selection options for different types of data, or enable different actions?
I.E. selecting a table item (row/cell???) choosing "Prepare Shipment" displaying an error if the item is "IsSecretlyABomb" 12/14/2015 4:27:14 PM |
FroshKiller All American 51913 Posts user info edit post |
Don't get it twisted. This isn't for the user to use. This is to speed up development of all these stupid damn screens.
Imagine two classes that represent things that are so dissimilar that you can't come up with many useful abstractions, right? Like...I don't know, fucking MagicMarker and RapLyrics.
I get the requests to add new dashboards or something for looking at collections of these items. The MagicMarker spec tells me that they definitely want to see columns for Color and IsNonToxic and IsErasable. The RapLyrics wants to see Artist, NumberOfBars, and IsObscene.
I don't want to write a bunch of friggin' bespoke code for pulling those specific properties for instances of the classes in the collections. I just want to have one piece of code that inspects the class to find all the properties that are, like, dashboard-appropriate and does the needful. And ideally, I'm not actually changing the class definitions for all the classes I'm using on these dashboards aside from tagging the properties with the appropriate attribute(s).
[Edited on December 14, 2015 at 4:41 PM. Reason : ///] 12/14/2015 4:31:48 PM |