MVC 3 with Dynamic Data - applying data types to Dynamic Data - asp.net-mvc-3

I have an MVC 3 C# / ADO.NET / Dynamic Data app set up and working(ish). To set it up I created an MVC 3 app, added the Dynamic Data components in, split out Presentation, Business and Data in to three projects, set the references to match the MVC pattern and set up the routes and scaffolding.
List, Edit and Insert all work with the standard DD page templates, however I've hit a wall getting the Presentation Layer to apply data type attributes to the data displayed in Gridview and Details views, particularly for URLs, which I want be typed as DataType.Url and so use the associated DD display attributes.
Have tried setting up a meta data class for the Link table and applying something like:
[DataType(DataType.Url)]
public object URL {get; set;}
(the Url field in table "Link" is "URL")
.. within a partial class, which is something I read about for pure DD sites.
Can anyone point me in the right direction, or tell me if is this even possible?
Many Thanks.

Yes this is possible. I would write a custom FieldTemplate for Urls. Using the UIHint metadata, you can assign a custom fieldtemplate to the column. Something like this (untested):
public partial class FooUrl : System.Web.DynamicData.FieldTemplateUserControl
{
string getUrl()
{
var metadata = MetadataAttributes.OfType<DataTypeAttribute>().FirstOrDefault();
if (metadata == null)
return FieldValueString;
switch (metadata.DataType)
{
case DataType.Url:
string url = FieldValueString;
if (url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
return url;
return "http://" + FieldValueString;
case DataType.EmailAddress:
return "mailto:" + FieldValueString;
default:
throw new Exception("Unknown DataType");
}
}
protected override void OnDataBinding(EventArgs e)
{
HyperLinkUrl.NavigateUrl = getUrl();
}
public override Control DataControl
{
get
{
return HyperLinkUrl;
}
}
}
}
I hope this helps.

Related

Add custom data-* attributes to Kendo UI AutoComplete or ComboBox

Currently using the Kendo UI AutoCompleteFor() and ComboBoxFor() helper.
Noticing that they generate/render a bunch of <li>s.
How does one add additional custom data-* attributes to those <li>s?
Here's the current scenario:
The user starts typing stuff in the AutoCompleteFor
An ajax call is triggered to fetch some data related to what the
user has typed.
The obtained results are transformed into an
IEnumerable<SelectListItem>.
The result is then sent to Json. Json(result, JsonRequestBehavior.AllowGet)
My goal is to add one or more additional data-* attribute to each of these <li> generate lines so that I can fetch these data-* in the onChange() event.
How does one achieve this?
In addition, I'm aware that I could create my own .Template() and possibly achieve my task but I was curious if anyone knows of a different way to do this then having to create my own template.
Sincerely
Ok I've found a solution; I'll share it here in case anyone is interested.
Instead of transforming my obtained results into an IEnumerable<SelectListItem>, I simply transform this into an IEnumerable<CustomDTO>.
The CustomDTO class looks like this:
public class CustomDTO
{
public int Value { get; set; }
public string Text { get; set; }
public int Age { get; set; }
//Add whatever more properties you think you’ll need.
}
In my controller, I then do the following:
var result = _myService.GetData().ToList();
return Json(result, JsonRequestBehavior.AllowGet);
Where GetData() returns an IEnumerable<CustomDTO>.
Inside my View, I have an AutoCompleteFor() control to which I bind a client side
.Events(x => x.Select("onSelect") event handler.
The handler is defined like so:
function onSelect(e)
{
if (e.item == null) return;
var dataItem = this.dataItem(e.item.index());
var valueAttribute = dataItem.Value;
var textAttribute = dataItem.Text;
var ageAttribute = dataItem.Age; //This is how I get my additional value
//...code...
}
So that's it.

Can I add a derived property to an EF entity and have it available to breeze?

I am using code first with an existing database, EF5, Web API and Breeze and I havent used any of these techs before. I am writing my own pocos.
I am trying to expose a read only property that requires several table joins to obtain the data. If we were using Web API only, we could just run some sql, populate the property and send some JSON back to the client.
Because we are using EF and breeze this obviously changes quite alot.
For example:
public class Employee
{
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[NotMapped]
public string FooBar
{
get { return getFooBar(); }
}
}
private string getFooBar()
{
// Do stuff here
}
This will send FooBar back to the client in the JSON result but because it is not mapped, and consequently not in the Metadata, I dont seem to be able to use it within Breeze.
I have read articles that say I can do this when using designer based methods (ie edit the edmx file) but how can it be done using code first?
I am aware that I can extend a Breeze entity on the client side but Im not really sure how I would get this value which hasnt been mapped, after Breeze has created all of the entities.
What I really want is to extend my code first entity. I also vaguely understand that this might not be in line with EF ideals but I also struggle with the idea that I dont have the freedom to define what is and what isnt a property of my employee.
I dont need to track changes. I dont need to save. I dont seem to be able the use the EF context provider to join the (many) tables and get the data because the entities for each table dont share a primary key and dont inherit from the same class.
I think this SO post here suggests something similar but once again its for generated classes. Is there a way to do this? Thanks.
Edit
In reply to Wards suggestion I tried a few tests.
My client side constructor:
function Employee() {
this.DisplayName = ""; // unmapped property
};
My Controller:
function TestController($scope, $routeParams) {
var manager = new breeze.EntityManager('breeze/employees');
var metadataStore = manager.metadataStore;
metadataStore.registerEntityTypeCtor("Employee", Employee);
var query = new breeze.EntityQuery()
.from("Employees")
.orderBy("FirstName");
manager.executeQuery(query).then(function (data) {
// Check unmapped property name
var employeeType = metadataStore.getEntityType("Employee");
var unmapped = employeeType.unmappedProperties;
alert(unmapped[0].name) // Returns 'DisplayName'
alert(employeeType.dataProperties[3].name) // Returns 'DisplayName'
var prop = manager.metadataStore.getEntityType('Employee').getProperty('DisplayName');
alert(prop.name) // Returns 'DisplayName'
var first = data.results[0]
var fullName = first.DisplayName
alert(fullName) // Returns empty string
$scope.employees = data.results;
$scope.$apply();
}).fail(function (e) {
alert(e);
});
};
My Angular:
<div>
<ul>
<li data-ng-repeat="employee in employees">
{{employee.DisplayName}}
</li>
</ul>
</div>
So the property seems to be setup correctly as an unmapped property, but it only returns the empty string. If I change
this.DisplayName = ""; // unmapped property
to
this.DisplayName = "Foo"; // unmapped property
then DisplayName always contains "Foo". The values from the payload are not being applied to DisplayName.
Am I missing something?
It's pretty easy on the Breeze client as explained in the Extending Entities documentation topic: you define an unmapped property in a custom constructor and register that constructor.
var metadataStore = myEntityManager.metadataStore;
metadataStore .registerEntityTypeCtor("Employee", Employee);
function Employee ()
this.FooBar = ""; // unmapped property
};
Now the Breeze metadata includes a definition of the FooBar unmapped property. The server will send a value for FooBar to the client and Breeze will populate that client Employee entity (unmapped) property when it materializes Employee entities from a query.
How you obtain that FooBar property value on the server is up to you. I don't know enough about your app. What you've shown us is a perfectly valid Code First entity definition.
Maybe you're asking an Entity Framework question rather than a Breeze question.
One way to get this working has been discussed in this SO answer from CassidyK. Here is the code snippet.
proto.initializeFrom = function (rawEntity) {
// HACK:
// copy unmapped properties from newly created client entity to the rawEntity.
// This is so that we don't lose them when we update from the rawEntity to the target.
// Something that will occur immediately after this method completes.
var that = this;
this.entityType.unmappedProperties.forEach(function(prop) {
var propName = prop.name;
that[propName] = rawEntity[propName]; // CassidyK
//rawEntity[propName] = that[propName]; // Breeze
});
if (!this._backingStore) {
this._backingStore = { };
}
};
I dont know what the side effects of this are. Perhaps one of the Breeze devs can better explain.
It seems this is only a problem when Breeze is configured for Angular.
IE
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);

How to get value dynamically added textbox values in MVC 3

I want to get the values of dynamically added Textbox on submit button in MVC 3.
I am storing the values in hidden field and getting using FromCollection. Is there any better approach?
If you name your values something like
MyValues[x] where x is a zero based, continuously increasing integer, you can receive the string values as a list of strings named MyValues.
This trick also works for properties if the main model object, if needed.
You should check some articles about how to bind to collections In ASP mvc, they could give you some ideas.
For example http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
You could do something like this (written very quickly outside of editor, so may have typos/issues):
Make a view model:
public class DynamicTextBoxViewModel
{
public IList<string> DynamicTextBox { get; set; }
public int OtherStuffInViewModel { get; set; }
}
Then in your Get Action:
var model = new YourViewModel
{
DynamicTextBoxList =
new List<DynamicTextBox>
{
new DynamicTextBox
{
TextBoxText = string.Empty,
}
},
OtherStuffInViewModel = xxx,
};
return View(model)
Then in your Post Action:
You would bind everything where you wanted it.
The idea is to move all the data into a ViewModel and pass that around so you gain the benefits of the ViewModel instead of passing around FormCollection - which is sloppier and more error prone.

Get full name of Complex Type from ModelClientValidationRequiredIfRule method in custom ValidationAttribute

I am using the example at The Complete Guide To Validation In ASP.NET MVC 3 to create a RequiredIf validation attribute (it's about 1/3 down the page under the heading of "A more complex custom validator"). It all works fine with the exception of one scenario, and that is if I have the need to validate against a complex type. For example, I have the following model:
public class MemberDetailModel
{
public int MemberId { get; set; }
// Other model properties here
public MemberAddressModel HomeAddress { get; set; }
public MemberAddressModel WorkAddress { get; set; }
}
public class MemberAddressModel
{
public bool DontUse { get; set; }
// Other model properties here
[RequiredIf("DontUse", Comparison.IsEqualTo, false)]
public string StreetAddress1 { get; set; }
}
The problem is that when the attribute validation for the StreetAddress property is rendered, it get's decorated with the attribute of data-val-requiredif-other="DontUse". Unfortunately, since the address is a sub-type of the main model, it needs to be decorated with a name of HomeAddress_DontUse and not just DontUse.
Strangely enough, the validation works fine for server-side validation, but client-side unobtrusive validation fails with an JS error because JS can't find the object with a name of just "DontUse".
Therefore, I need to find a way to change the ModelClientValidationRequiredIfRule method to know that the property it is validating is a sub-type of a parent type, and if so, prepend the ParentType_ to the "otherProperty" field (e.g. otherProperty becomes HomeAddress_DontUse.
I have tried passing in typeof(MemberAddressModel) as a parameter of the attribute, but even when debugging the attribute creation, I can't seem to find any reference to the parent type of HomeAddress or WorkAddress from that type.
Based on the suggestion from The Flower Guy, I was able to come up with the following which seems to work. I simply modified the following in the customValidation.js file:
jQuery.validator.addMethod("requiredif", function (value, element, params) {
if ($(element).val() != '') return true;
var prefix = getModelPrefix(element.name); // NEW LINE
var $other = $('#' + prefix + params.other); // MODIFIED LINE
var otherVal = ($other.attr('type').toUpperCase() == "CHECKBOX") ? ($other.attr("checked") ? "true" : "false") : $other.val();
return params.comp == 'isequalto' ? (otherVal != params.value) : (otherVal == params.value);
});
I also added the following method to that file (within the JQuery block so as to be only privately accessible):
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1).replace(".","_");
}
Cannot do it exactly right now, but the problem is in the client javascript function:
jQuery.validator.addMethod("requiredif" ...
The js is not sophisticated enough to cope with complex view models where there may be a model prefix. If you take a look at Microsoft's jquery.validate.unobstrusive.js (in the Scripts folder over every MVC3 application), you will find some useful methods including getModelPrefix and appendModelPrefix. You can take a similar approach and change the requiredIf validation method - take a look at the equalto method in jquery.validate.unobstrusive.js for a helping hand.

How do I implement ASP.NET MVC 2 validation that checks the database?

All examples that I can find do something like this:
[Required]
public string Title { get; set; }
That's great for simple cases, but what about something that checks the database or something else server side?
For example, say I have a movie database and I want to allow people to rate it. How could I tell if someone has already rated a movie, as I'd only want them to rate a movie once.
I would think it would be something like:
public IEnumerable<string> ValidateUserHasNotAlreadyRatedMovie(User currentUser, Guid movieId)
{
if(movieHasAlreadyBeenRated)
{
yield return "Movie been rated man!";
}
}
Now then I'd call this with something like:
var errors = new List<string>();
errors.AddRange(ValidateUserHasNotAlreadyRatedMovie(topic, comment));
if(errors.Any())
{
throw new SomeTypeOfCustomExtension??(errors);
}
Do I just need to extend Exception for a custom SomeTypeOfCustomExtension above, or is there something already built? Am I doing this the ASP.NET MVC 2 way?
After that how do I put it into the model state and let the view know something's wrong?
See this it may help
Remote Validation with ASP.NET MVC 2
http://bradwilson.typepad.com/blog/2010/01/remote-validation-with-aspnet-mvc-2.html
The ASP.NET 2.0 MVC way of doing custom validation is described here. It basically shows how to write a custom validation attribute. Here is an example of one such custom attribute that checks the database for name uniqueness:
public class UniqueNameAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
string str = (string)value;
if (String.IsNullOrEmpty(str))
return true;
using (XDataContext vt = new XDataContext())
{
return !(vt.Users.Where(x => x.Username.Equals(str)).Any());
}
}
}
The ASP.NET 1.0 way (that doesn't require custom attributes) is described here.

Resources