Say you had a config object
public class MyConfig{
public int PageSize{get;set;}
public string Title{get;set;}
}
and you want to automatically generate a asp.net form to edit the properties on this object.
Do you know of any frameworks to do this automagically?
I know of MS Dynamic data, but seems I need to have the whole stack (database, linq, objects) to get this up and running. So I was thinking of something simpler..
Sorry for jumping in late. There are several ways to use Dynamic Data with POCO.
Use the DynamicObjectDataSource which is found in Futures and Preview releases of Dynamic Data, starting with July 2008 Futures. When looking in a Preview release, it contains a Futures assembly, Microsoft.Web.DynamicData.dll.
When using ASP.NET 4.0 (now in Beta), you can call a new extension method, EnableDynamicData(). See the "SimpleDynamicDataSamples" project that comes with DD Preview 4 and later.
Here's an example from that code that uses an ObjectDataSource and the POCO class called "Product".
[MetadataType(typeof(Product.Metadata))]
public partial class Product {
public class Metadata {
[Required]
public string ProductName { get; set; }
[Range(0, 100)]
public decimal UnitPrice { get; set; }
}
}
public partial class ObjectDataSourceSample : System.Web.UI.Page {
protected void Page_Init() {
// Extension method syntax
ProductsList.EnableDynamicData(typeof(Product));
// Explicit syntax
// MetaTable table = MetaTable.CreateTable(typeof(Product));
// MetaTable.MapControl(ProductsList, table);
// ProductsList.ColumnsGenerator = new DefaultAutoFieldGenerator(table);
}
}
I was under the impression that you could modify the T4 templates used by dynamic data (Not sure if you can remove the data access part).
Have you looked at just using T4 on its own.
Related
I have a project consisting of 2 parts:
ASP.NET API using Entity Framework
.NET MAUI Client App
I use DTOs for comunication from/to the API in order not to expose other properties of my entities. Thanks to this approach I was able to separate Entity data and data that are sent from the API.
At first I used these DTOs also in the MAUI UI. But after some time I started to notice that they contains UI-specific properties, attributes or methods that have no purpose for the API itself, so they are redundant in requests.
EXAMPLE:
1 - API will receive request from MAUI to get exercise based on it's name
2- ExerciseService returns: ExerciseEntity and ExerciseController use AutoMapper to Map ExerciseEntity -> ExerciseDto ommiting ExerciseId field (only admin can see this info in the DB) and returning it in the API response
3 - MAUI receives from the API ExerciseDto. But in the client side it also want to know if data from ExerciseDto are collapsed in the UI. So because of that I add IsCollapsed property into the ExerciseDto. But now this is a redundant property for the API, because I dont want to persist this information in the database.
QUESTIONS:
Should I map these DTOs to new objects on the client side ?
Or how to approach this problem ?
Is there an easier way how to achieve the separation ?
Because having another mapping layer will add extra complexity and a lot of duplicate properties between DTOs and those new client objects.
Normally if you use clean architecture approach your DTOs shoud contain no attributes and other specific data relevant just for some of your projects, to be freely usable by other projects in a form of dependency.
Then you'd have different approaches to consume DTOs in a xamarin/maui application, for example:
APPROACH 1.
Mapping (of course) into a class that is suitable for UI. Here you have some options, use manual mapping, write your own code that uses reflection or use some third party lib using same reflection. Personally using all of them, and when speaking of third party libs Mapster has shown very good to me for api and mobile clients.
APPROACH 2.
Subclass DTO. The basic idea is to deserialize dto into the derived class, then call Init(); if needed. All properties that you manually implemented as new with OnPropertyChanged will update bindings after being popupated by deserializer/mapper and you alse have a backup plan to call RaiseProperties(); for all of the props, even thoses who do not have OnPropertyChanged in place so they can update bindings if any.
Example:
our Api DTO
public class SomeDeviceDTO
{
public int Id { get; set; }
public int Port { get; set; }
public string Name { get; set; }
}
Our derived class for usage in mobile client:
public class SomeDevice : SomeDeviceDTO, IFromDto
{
// we want to be able to change this Name property in run-time and to
// reflect changes so we make it bindable (other props will remain without
// OnPropertyChanged BUT we can always update all bindings in code if needed
// using RaiseProperties();):
private string _name;
public new string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
OnPropertyChanged();
}
}
}
// ADD any properties you need for UI
// ...
#region IFromDto
public void Init()
{
//put any code you'd want to exec after dto's been imported
// for example to fill any new prop with data derived from what you received
}
public void RaiseProperties()
{
var props = this.GetType().GetProperties();
foreach (var property in props)
{
if (property.CanRead)
{
OnPropertyChanged(property.Name);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
public interface IFromDto : INotifyPropertyChanged
{
//
// Summary:
// Can initialize model after it's being loaded from dto
void Init();
//
// Summary:
// Notify all properties were updated
void RaiseProperties();
}
We can get it like: var device = JsonConvert.DeserializeObject<SomeDevice>(jsonOfSomeDeviceDTO);
We then can call Init(); if needed..
Feel free to edit this answer to add more approaches..
Does any one have a working example of how to added audit models to an existing project, for Audit.Net.
It is one fantastic component to use, and up until now, my team and I have gotten by with the standard JSON files, however, we'd like to migrate our current solution to our Xamarin application, and would like to store the auditing in the local SQLite database on the device.
However, the documentation for this project is somewhat lacking and there is no concise examples of how to get custom auditing working with Entity Framework.
We have worked through the MD files on the github repo, but we still cannot get auditing to work.
Another question, similar to this has been asked HERE, but there is no definitive example of what the Audit_{entity} table should look like, what fields it MUST contain, and how to set up relationships for it.
We tried to reverse engineer the JSON files into a relational structure, but at the time of asking this question, we have not gotten any auditing to write to the SQLite database.
Sorry about the documentation not helping too much, hope I (or anybody) can provide better documentation in the future.
I am assuming you are using EntityFramework to map your entities
to a SQLite database, and you want to use the EF data
provider
to store the audits events in the same database, in Audit_{entity} tables.
There is no constraint on the schema you want to use for your Audit_{entity} tables, as long as you have a one-to-one relation between your {entity} table and its Audit_{entity} table. Then the mapping can be configured on several ways.
The recommendation for the Audit_{entity} tables is to have the same columns as the audited {entity} table, with any common additional column needed, like a User and a Date defined on an Interface.
So, if all your Audit_{entity} tables has the same columns/properties as its {entity}, and you added some common columns (defined on an interface), the configuration can be set like this:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Audit_User : IAudit
{
public int Id { get; set; }
public string Name { get; set; }
// IAudit members:
public string AuditUser { get; set; }
public datetime AuditDate { get; set; }
public string Action { get; set } // "Insert", "Update" or "Delete"
}
Audit.Core.Configuration.Setup()
.UseEntityFramework(x => x
.AuditTypeNameMapper(typeName => "Audit_" + typeName)
.AuditEntityAction<IAudit>((ev, ent, auditEntity) =>
{
auditEntity.AuditDate = DateTime.UtcNow;
auditEntity.AuditUser = evt.Environment.UserName;
auditEntity.AuditAction = ent.Action;
});
Note the interface is not mandatory, but using it makes the configuration cleaner. Also note you can make your Audit_{entity} inherit from your {entity} if you wanted to.
Update
Maybe my assumption at the beginning is incorrect and you are not auditing EF entities, but any other type of audit. If that's the case, what you are looking for is a Data Provider that stores the audit events into your SQLite database.
At the time being, there is no built-in data provider that stores to SQLite, and if there was one, it would store just the JSON representation of the event in one column (like the SQL/MySql providers). But it looks like you want to have a custom schema, so you will need to implement your own data provider.
Check the documentation here.
Here is a sample skeleton of a data provider:
public class SQLiteDataProvider : AuditDataProvider
{
public override object InsertEvent(AuditEvent auditEvent)
{
// Insert the event into SQLite and return its ID
}
public override void ReplaceEvent(object eventId, AuditEvent auditEvent)
{
// Replace the event given its ID (only used for CreationPolicies InsertOnStartReplaceOnEnd and Manual)
}
// async implementation:
public override async Task<object> InsertEventAsync(AuditEvent auditEvent)
{
// Asynchronously insert the event into SQLite and return its ID
}
public override async Task ReplaceEventAsync(object eventId, AuditEvent auditEvent)
{
// Asynchronously replace the event given its ID
}
}
Then you just set it up with:
Audit.Core.Configuration.Setup()
.UseCustomProvider(new SQLiteDataProvider());
Details:
ASP.Net MVC 5
.Net 4.5
MVVM
Entity Framework 6 Code First
I have ViewModels with complex properties on them. I have read about how I can use the BindAttribute to include or exclude properties for model bidning and got basic properties working with this.
However one thing I cannot find is how to control the binding of child properties within a collection property. For example I have the following
[Bind(Include = "Model.Id, Model.Positions.StartDate")]
public class ProjectViewModel
{
public Project Model {get;set;}
public ProjectViewModel(Project project)
: base(project)
{
Model = project;
}
public ProjectViewModel()
{
}
}
A Project has a list of Positions:
public class Project : BaseEntity
{
.
.
.
public virtual IList<Position> Positions
{
get;
set;
}
}
And a Position has a start and end date:
public class Position : BaseEntity
{
[SensibleDateTime]
public DateTime StartDate { get; set; }
[SensibleDateTime]
public DateTime EndDate { get; set; }
[Required]
[ForeignKey("Project")]
public Int64 ProjectID { get; set; }
public virtual Project Project { get; set; }
}
I have a screen using the Project View Model with a grid of positions where the user is allowed to change the start and end date of those positions. I do not want to allow them to let them amend any other properties of the Position including by manipulating the request / post to the server.
I am writing my own custom model binder which inherits from the DefaultModelBinder which gets the original entity out the database. I just want to bind permitted bound fields on top to get these new values and all the original values will already exist.
I am aware I could get the original entity out the database inside the controller instead and map the bound start and end date onto the entity manually. I want to avoid this if possible and make the controller code as simple as possible as this will be a very common task. Additionally it seems like using standard MVC mechanisms would be the preferred approach.
I have tried the following bind statement on the Project View Model:
[Bind(Include = "Model.Positions.StartDate")]
None of the new values are bound including the start date of the positions. If I write a simple include for a property directly on the Project View Model or Model it works.
How do you write a Bind attribute statement that refers to a property within an entity collection?
I can't say for sure as I never use the Bind attribute, but the dot syntax should work. However, I'm reasonably sure that Bind focuses on the posted name, not the actual model property. In other words, you would most likely need to do something like "Positions[0].StartDate,Positions[1].StartDate,...".
In general, it's far better to just use view models to only include the properties you want to be editable.
I have a legacy asp.net web application which has 2 layers , UI and BusinessLayer. The UI project is of type ASP.NET website and BL is of type class library. The BL project has classes for entities of my app like Customer,User,Empoloyee etc.. Each class has methods for Reading from Database and Populate the object properties from the DataReader.that means the Customer Class contains my Customer object and Data Access Methods together.
Now I changed the web app to support MVC too. The old site (webforms) works as it used to be and the new upgrade to the site i am making (adding admin features to manage the site) is in ASP.NET MVC3. The routing and everything works fine. But i am worried about the structure /maintainability of the project.
For the new MVC part, I had to create ViewModels for few of the Entities like CustomerViewModel,EmployeeViewModel. I created another class called "CustomerService" With methods like GetCustomerViewModel and inside that method i call the GetCustomerMethod from the Existing BusinessLayer and read property values from the object ( of entity type mentioned in the existing BL project) and assign that to the CustomerViewModel (I will look into some AutoMapper samples for this later)object and return that from this method. My View will use this object to show data in the UI. The reason i created the "CustomerService" class is i may need to do some if condition checking or some business validations before setting the values to CustomerViewModel object. I consider that as a "Middle Layer / Service layer" so that my Controllers will be thin.
From my Customer Controller
public ActionResult Details(int id)
{
MyProject.MVCViewModel.CustomerViewModel objCustomerVM;
objCustomerVM=MyProject.MVCMiddleLayer.CustomerService.GetCustomerViewModel(id);
return View(objCustomerVM);
}
In my CustomerViewModel
public static CustomerViewModel GetCustomerViewModel(int customerId)
{
//Create an object of new ViewModel
CustomerViewModel objCustomerViewModel = new CustomerViewModel ();
//Get an object from Existing BL of Customer of type ExistingBL.Customer
ExistingBL.Customer objCustOld=new Customer(customerId);
//Check some properties of the customer object and set values to the new ViewModel object
if(objCustOld.Type=="normal")
{
objCustomerViewModel.Priority=2;
}
else if(objCustOld.Type=="abnormal")
{
objCustomerViewModel.Priority=1;
objCustomerViewModel.Message ="We love you";
}
//Some other checking like this....
return objCustomerViewModel;
}
Is this a wrong approach ? Is my code going to be messy ? I am not happy about the ViewModel since it is (almost) the duplicate code from my Existing BL entities. What is the best way to address this scenario. I am not sure about using Repository Pattern (which i saw in most of the examples) in this case ? Should i do that ?How is it going to improve my code ?
The approach that I would take would be similar to repository pattern. I would outline few key points
Since the only thing that you would be rewriting would be UI logic (View Model Object), and its fine as your UI technologies are different(asp.net vs MVC)
I would suggest you start working on interfaces so that later on you could do a dependency injection. The biggest benefit I generally with dependecy injection in mvc is while writing NUnit test cases.
public static ICustomerViewModel GetCustomerViewModel(int customerId)
{
//use DI, rather than concerete implementation
ICustomerViewModel objCustomerViewModel = new CustomerViewModel ();
//use DI, rather than concerete implementation
ExistingBL.ICustomer objCustOld=new Customer(customerId);
.
.
.
return objCustomerViewModel;
}
You could now very easily create mock objects with the help of any mocking frame work.
More or less my ViewModel classes are a redefinition of properties with only attributes, someone may argue that this is just another overhead layer, but I do this for a simple reason: I can add proper Web Validation's attributes without breaking anything (The DataLayer shoudl be shareable with other apps).
In shorts given a DataLayer class exposing a User object:
public class DalUser {
public int Id { get; set;}
public int Age { get; set;}
public string Name { get; set;}
public string Surname { get; set;}
// Business method for reading/writing/deleting
}
My viewmodel is something like:
public class VmUser : DalUser
{
[Display(Name="ID Code")]
public override int Id { get; set; }
[Display(Name="Age")]
[Required]
public override int Age { get; set; }
}
This leads me to two goals: the former is I can use Attributes without worrying about breaking something else, the latter is I can hide from user some field, prevent field injection (e.g. from FireBug - but that's includes defining an Interface and using that, not plain subclassing).
That's proves pretty usefull within my corporate (we're doomed to use EntitySpaces) and it's one of the less ugly way I've found in order to partially reuse ES generated classes.
Does anybody know if it is possible to choose the order of the fields in Dynamic Data (of course, without customizing the templates of each table) ?
Thanks !
In .NET 4.0, using the 4.0 release of the Dynamic Data dll, you can set data annotations like so:
[Display(Name = " Mission Statement", Order = 30)]
public object MissionStatement { get; set; }
[Display(Name = "Last Mod", Order = 40)]
public object DateModified { get; private set; }
As per this thread - you can use the ColumnOrderAttribute in the dynamic data futures dll. You can grab the futures from codeplex.
You can do this by modifying the order of the public properties in your LINQ to SQL file.
For example, I went into Northwind.designer.cs which was my auto-generated LINQ to SQL file and moved the public property named Products above the public property CategoryName in the public partial class Category. Then I recompiled and the default template displayed the columns in my new order.
Of course, this means your editing auto-generated code and if you regenerate it, your changes are lost, so this technique is not without peril.
You have to create a custom page in DynamicData folder.
Here are the steps:
Create a folder that is the same name as your table name that you want to customize the ordering of columns under "DynamicData\CustomPages" folder
Create a custom page under "DynamicData\CustomPages\[folder with table name]" folder.
I just copy the existing "List.aspx" file from "DynamicData\PageTemplates" into the folder above.
Open the aspx file and modify GridView control to "AutoGenerateColumns='false'"
Inside columns section of GridView, add "DynamicControl" controls with the "DataField" attribute value to the name of your column in the order you want.
Here is a screencast from ScottHa:
http://www.asp.net/learn/3.5-SP1/video-293.aspx
GridView have ColumnsGenerator property, use it by implementing GenerateFields method of IAutoFieldGenerator interface in which you can set fields orders based on your custom rules (attributes, meta info, ...)
protected override void OnInit(EventArgs e)
{
...
this.gvItemsList.ColumnsGenerator = new EntityFieldsGenerator(CurrentDataSource.CurrentTableMetadata);
...
}
public class EntityFieldsGenerator : IAutoFieldGenerator {
...
public ICollection GenerateFields(Control control)
{
// based on entity meta info
var fields = from item in this.entityMetadata.Columns
where this.IncludeColumn(item.Value)
orderby item.Value.Order
select new DynamicField
{
DataField = item.Value.Column.Name,
HeaderText = item.Value.DisplayName,
DataFormatString = item.Value.DataFormatString,
UIHint = GetColumnUIHint(item.Value)
};
return fields.ToList();
} }
To avoid using the Dynamic Data futures dll, you can roll your own ColumnOrder attribute as follows:
[AttributeUsage(AttributeTargets.Property)]
public class ColumnOrderAttribute : Attribute
{
public int Order { get; private set; }
public ColumnOrderAttribute() { Order = int.MaxValue; }
public ColumnOrderAttribute(int order) { Order = order; }
public static ColumnOrderAttribute Default = new ColumnOrderAttribute();
}
and then in your class that implements IAutoFieldGenerator, you have
public static class ExtensionMethods
{
public static int GetOrder (this MetaColumn column)
{
var orderAttribute = column.Attributes.OfType<ColumnOrderAttribute>().DefaultIfEmpty(ColumnOrderAttribute.Default).Single();
return orderAttribute.Order;
}
}
public ICollection GenerateFields(Control control)
{
var fields = new List<DynamicField>();
var columns = _table.Columns.OrderBy(column => column.GetOrder());
foreach (var column in columns)
{
if (!column.Scaffold) { continue; }
fields.Add(new DynamicField {DataField = column.Name});
}
}
and finally your usage would look like
[MetadataType(typeof(CustomerMetadata))]
public partial class Customer {}
public class CustomerMetadata
{
[ColumnOrder(1)]
public object FirstName {get;set;}
[ColumnOrder(2)]
public object LastName {get;set;}
}
I'm answering an old question because it seems to me that the possible solution changed in newer versions of the framework.
It seems that the Display(Order) works now directly as asked (Visual Web Developer 2010 on .NET 4.0) without any particular workaround.
Example:
[Display(Order = 50)]
An important thing it's to check the correct object name to map the foreignkey:
in one project a field OperatoreID translated in the entity class as:
public object Operatore { get; set; }
being Operatore the source table of the foreignkey; for a second reference on the same table it will get something like 1 and so on.