Best practices for binding MVC model to WCF service through "datamodule"? - wcf

I'm somewhat of a noob, so bear with me please.
I'm building an MVC project that gets data from a web service (WCF) as exposed by a "datamodule" class that passes parameters to the service. Right now what I have is a viewmodel that looks like this:
public String FirstName { get; set; }
public String LastName { get; set; }
public String DisplayName { get; set; }
public String Role { get; set; }
A "datamodule" class that looks like this:
private readonly ServiceClient _serviceClient = new ServiceClient();
public List<Info> GetStuff(int Id)
{
return _serviceClient.GetStuff(Id);
}
And a controller action that looks like this:
var dm = new DataModule();
var members = dm.GetStuff(96);
var team = from member in members
select new TeamModel
{
FirstName = member.FirstName,
LastName = member.LastName,
Role = member.Role,
DisplayName = member.DisplayName
};
return PartialView(team.ToList());
I don't feel like it's very clean (or MVC like) to manually bind data like this in every one of my controllers. Is there a best practices way to bind data like this?

Related

how to implement computed field for model in web api odata using EF 6

I'm creating a web api odata controller and all is well until I try to add a derived field to the model. I don't want the field to exist in the database, and the field does not need to be queryable.
Given model;
public class Foo
{
public Int64 Id { get; set; }
public string SomeDatabaseSourcedField{ get; set; }
public string SomeDerivedField{ get; set; }
}
If I've got a controller like;
private FooDbContext db = new FooDbContext();
[Queryable]
public IQueryable<Foo> GetFoo()
{
return db.Foo;
}
How do it set the value of SomeDerivedField?
Note: I've tried marking the field as not mapped but it seems the field does not get returned in api calls.
Here is my answer, What I'm using is odata v4. http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/
I've successfully get the derived field in the response.
First, define a class which derives from foo:
public class MyFoo:Foo
{
public string SomeDerivedField{ get; set; }
}
Second, build the edm model:
public static IEdmModel GetModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<MyFoo>("Foo");
builder.EntityType<MyFoo>().DerivesFromNothing();
builder.Namespace = typeof(MyFoo).Namespace;
return builder.GetEdmModel();
}
Third, retrieve the data:
public IHttpActionResult Get()
{
IQueryable<MyFoo> foos= db.Foos.Select(
t => new MyFoo()
{
Id = t.Id,
Name = t.Name,
SomeDerivedField= t.Name + SqlFunctions.StringConvert((double)t.Id)
});
return Ok(foos);
}

this[propertyName] is not a function in breeze.debug.js

I am using Hot towel template and extended functionality of it by using breeze. I have used breeze.partial-entities.js file to conver breeze entities to proper dtos that can be used by knockout observables as shown below.
function dtoToEntityMapper(dto) {
var keyValue = dto[keyName];
var entity = manager.getEntityByKey(entityName, keyValue);
if (!entity) {
// We don't have it, so create it as a partial
extendWith = $.extend({ }, extendWith || defaultExtension);
extendWith[keyName] = keyValue;
entity = manager.createEntity(entityName, extendWith);
}
mapToEntity(entity, dto);
entity.entityAspect.setUnchanged();
return entity;
}
For few of the entities it is working properly and getting breeze data converted to entities but for one of the entity implementation is failing. Model for the same is given as below.
public class StandardResourceProperty
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int StandardResourceId{ get; set; }
public int InputTypeId{ get; set; }
public int ListGroupId{ get; set; }
public string Format{ get; set; }
public string Calculation{ get; set; }
public bool Required{ get; set; }
public int MinSize{ get; set; }
public int MaxSize{ get; set; }
public string DefaultValue{ get; set; }
public string Comment { get; set; }
public virtual StandardResource AssociatedStandardResource { get; set; }
public virtual List AssociatedList { get; set; }
}
The error i am getting is
TypeError: this[propertyName] is not a function
[Break On This Error]
thispropertyName;
breeze.debug.js (line 13157)
]
with code
proto.setProperty = function(propertyName, value) {
this[propertyName](value);
// allow set property chaining.
return this;
};
Please let me know . What can be possible issue with the implementation also , it would be great if i can get more suggestion on how to debug and trace such issues.
Let's back up. I do not understand what you mean by "convert breeze entities to proper dtos that can be used by knockout observables". Breeze entities are already configured as KO observables (assuming you are using the default Breeze model library configuration). What are you trying to do?
I suspect you are following along with the Code Camper Jumpstart course where it does a getSessionPartials projection query. That query (like all projections) returns DTOs - not entities - and maps them with the dtoToEntityMapper method into Session entities.
The CCJS dtoToEntityMapper method cannot be used with entities. It is for converting from a DTO to an Entity and takes DTOs - not entities - as input.
Goodbye to dtoEntityMapper
The dtoToEntityMapper method pre-dates the ability of Breeze to automate projection-to-entity mapping by adding .toType('StandardResourceProperty') to your projection query.
Here is what the CCJS getSessionPartials query could look like now:
var query = EntityQuery
.from('Sessions')
.select('id, title, code, speakerId, trackId, timeSlotId, roomId, level, tags')
.orderBy(orderBy.session)
.toType('Session');
If you go this way, be sure to set the default state of the isPartial flag to true in the custom constructor (see model.js)
metadataStore.registerEntityTypeCtor(
'Session', function () { this.isPartial = true; }, sessionInitializer);
Note that this.isPartial = true is the reverse of the CCJS example where the default was false.
Make sure that you set isPartial(false) when you query or create a full entity. In CCJS there are two places to do that: in the success-callback of getSessionById AND in createSession which would become:
var createSession = function () {
return manager.createEntity(entityNames.session, {isPartial: false});
};

BreezeJS Get Metadata from the server without using Entity Framework for complex objects (nested objects)

This is my model on the server side. I don't want to use Entity Framework, how would I generate BreezeJS metadata from the server. Breeze Metadata Format found here http://www.breezejs.com/documentation/breeze-metadata-format doesn't work.
public class User
{
public string Id { get; set; }
public string Name { get; set; }
public List<App> Apps { get; set; }
}
public class App
{
public string Id { get; set; }
public string Name { get; set; }
public Dictionary<string, string> Info { get; set; }
}
Did anyone try complex objects (nested object) similar to above one without using EF.
Using Breeze Metdata API or OData ?
Look at this example http://www.breezejs.com/samples/nodb it should give you a clue.

Nested LINQ IQueryable and WCF WebApi

I have a method like this that works as expected.
[WebGet]
public IQueryable<BuildJobModel> GetCustomers()
{
var context = new MyDataContext(); // ADO.NET Entity Data Model
var query = from c in context.Customers
select new CustomerModel {
Id = c.Id,
Name = c.Name
};
return query;
}
But when I try to create a more complex query like this, it doesn't work.
[WebGet]
public IQueryable<BuildJobModel> GetCustomers()
{
var context = new MyDataContext(); // ADO.NET Entity Data Model
var query = from c in context.Customers
select new CustomerModel {
CustomerId = c.CustomerId,
Name = c.Name,
Orders = from o in c.Orders
select new OrderModel {
OrderId = o.OrderId,
Details = o.Details
}
};
return query;
}
The Models look like this:
public class CustomerModel
{
public int CustomerId { get; set; }
public string Name { get; set; }
public IEnumerable<OrderModel> Orders { get; set; }
}
public class OrderModel
{
public int OrderId { get; set; }
public string Details { get; set; }
}
The Exception:
Cannot serialize member Proj.CustomerModel.Logs of type System.Collections.Generic.IEnumerable`1[[Proj.OrderModel, Proj, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] because it is an interface.
My Goals:
I want to be able to expose an IQueryable interface.
I want to return nested data.
I want to use my own Models, not the ado.net entities
I want to hit the database with as few queries as possible (one would be best).
I would strongly recommend not exposing IQueryable as a return type of a WCF service.
WCF was designed to return data not queries
You lose control over the nature of the query: someone might potentially use this query in a way that is resource-intensive
Ideally, if you want to return collections use array or a generic list.
With respect to your list of goals:
Can you explain this? I don't see what IQueryable interface has to do with nested data.
You can still return arrays or lists of your models
You have better control over performance if you execute query locally and return results instead
Update: Have a look at WCF Data Services - that might be able to do what you want.
In case you're trying to return JSON: the build in JsonFormatter is not able to (de)serialize interfaces. You should try the JSON.NET Formatter from WebApiContrib.
I think you just need to use an array rather than IEnumerable, like so...
public class CustomerModel
{
public int CustomerId { get; set; }
public string Name { get; set; }
public OrderModel[] Orders { get; set; }
}
public class OrderModel
{
public int OrderId { get; set; }
public string Details { get; set; }
}
If you're serializing this to json/xml I suspect the built-in serializers don't know what to do with IEnumerable.

WebApi HttpClient help getting collection (version .6)

I am calling on a WCF Data Services v3 Odata service.
I am having trouble getting my collection filled in the below example. I am able to get a json string of the 3 people, but if I try and get a custom collection filled, the collection has a count = 0.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.BaseAddress = new Uri("http://localhost:7500/Wcf1.svc/People");
HttpResponseMessage resp = client.GetAsync("").Result;
string jsonString = resp.Content.ReadAsStringAsync().Result;
List<Person> personCollection = resp.Content.ReadAsAsync<List<Person>>().Result;
jsonString has 3 people in it.
personCollection has a count = 0.
the jsonString looks like this:
{"d":[
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(1)",
"uri":"http://localhost:7500/Wcf1.svc/People(1)",
"type":"WcfService1.Person"},
"ID":1,"Fname":"Fred","Lname":"Peters","Address1":"123 Main"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(2)",
"uri":"http://localhost:7500/Wcf1.svc/People(2)",
"type":"WcfService1.Person"},
"ID":2,"Fname":"John","Lname":"Smith","Address1":"123 Oak"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(3)",
"uri":"http://localhost:7500/Wcf1.svc/People(3)",
"type":"WcfService1.Person"},
"ID":3,"Fname":"Tom","Lname":"Anders","Address1":"123 Hill St."}]}
I must be doing something wrong, please point out my error if you can.
Thanks.
Terrence
Your content is not a List<Person>
Paste your Json into json2csharp and you'll see it.
To get a better overview what your response content is, download Json Viewer - this is a screenshot of your data:
As you can see: the Persons are a property of the Json root object.
If you wanted to use your code from above, the Json should have to look like this (or you need to access the data in the given structure mapping you classes according to the Json):
[{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(1)",
"uri":"http://localhost:7500/Wcf1.svc/People(1)",
"type":"WcfService1.Person"},
"ID":1,"Fname":"Fred","Lname":"Peters","Address1":"123 Main"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(2)",
"uri":"http://localhost:7500/Wcf1.svc/People(2)",
"type":"WcfService1.Person"},
"ID":2,"Fname":"John","Lname":"Smith","Address1":"123 Oak"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(3)",
"uri":"http://localhost:7500/Wcf1.svc/People(3)",
"type":"WcfService1.Person"},
"ID":3,"Fname":"Tom","Lname":"Anders","Address1":"123 Hill St."}]}]
Update:
You should be able to parse your initially posted Json like this:
var json = JsonValue.Parse(response.Content.ReadAsStringAsync().Result);
var arr = json["d"];
var contact1 = arr[0];
var fname = result1["Fname"];
I have done a blog post on JsonValue and JsonArray recently. It's server side, but it should point you the direction.
2nd Update:
Using the classes from the json2csharp.com output, you can do this:
public class Metadata
{
public string id { get; set; }
public string uri { get; set; }
public string type { get; set; }
}
public class D
{
public Metadata __metadata { get; set; }
public int ID { get; set; }
public string Fname { get; set; }
public string Lname { get; set; }
public string Address1 { get; set; }
}
public class RootObject
{
public List<D> d { get; set; }
}
Usage:
var root = resp.Content.ReadAsAsync<RootObject>().Result;
var persons = root.d;
var person1 = persons[0];