Is breeze server side metadata mandatory or can it be be defined client-side?
Asked Answered
N

3

6

I am looking in to using breezejs and have a few questions in terms of its capabilities and the best practices that come with it.

  1. Does server side metada have to exist? If I have a non EF WebApi controller do I still have to wrap it with the ProviderContext and implement metadata? If so, what is the format of the metadata?
  2. If I am able to omit metadata on the server side and just implement the queryable actionfilter, can I still write client side code to define the metadata? Where would I find information on how to do this?
  3. I have a server Model class called Job with an id and name, which are simple properties and an object property called Company which points to a server side model class called Company which has an id and name. Job(s) can be confidential (through a boolean IsConfidential property on Job) in which case even though they still have a companyId, that property should not be sent to the client. Instead there should be a server-side computed property called CompanyName (basically Company.Name for non-confidential Jobs and "Confidential" for confidential jobs) that is sent to the client. Admin roled users should be able to see and edit CompanyId but regular users should not be able see or post/put that value. How do you accomplish this in breeze? Does breeze deal well with sending and receiving non-Model ViewModels (less properties and some computed properties)?
  4. Is the source for the source code for the ODataActionFilter something I can use and change for any purpose I want?
  5. How difficult would it be to create WebApi Controllers for something other than EF - maybe like Telerik OpenAccess?

Thanks

Natality answered 28/11, 2012 at 14:44 Comment(0)
B
6

Pawel's post is correct that you should start by calling

breeze.config.initializeAdapterInstances

To actually create the client side metadata you would write something like this. ( A simple example).

initializeMetadataStore(myEntityManager.metadataStore);

function initializeMetadataStore(metadataStore) {
    var et = new EntityType({
        shortName: "Person",
        namespace: "Sample_WebApi.Models"
    });
    et.addProperty( new DataProperty({
        name: "personId",
        dataType: DataType.Int32,
        isNullable: false,
        isPartOfKey: true,
    }));
    et.addProperty(new DataProperty({
        name: "firstName",
        dataType: DataType.String,
        isNullable: false,
    }));
    et.addProperty(new DataProperty({
        name: "lastName",
        dataType: DataType.String,
        isNullable: false,
    }));
    et.addProperty(new DataProperty({
        name: "birthDate",
        dataType: DataType.DateTime,
        isNullable: true
    }));
    et.addProperty(new NavigationProperty({
        name: "meals",
        entityTypeName: "Meal",
        isScalar: false,
        associationName: "personMeals"
    }));
    metadataStore.addEntityType(et);

    et = new EntityType({
        shortName: "Meal",
        namespace: "Sample_WebApi.Models"
    });
    et.addProperty(new DataProperty({
        name: "mealId",
        dataType: DataType.Int32,
        isNullable: false,
        isPartOfKey: true,
    }));
    et.addProperty(new DataProperty({
        name: "personId",
        dataType: DataType.Int32,
        isNullable: false,
    }));
    et.addProperty(new DataProperty({
        name: "dateConsumed",
        dataType: DataType.DateTime,
        isNullable: false,
    }));
    et.addProperty(new NavigationProperty({
        name: "person",
        entityTypeName: "Person",
        isScalar: true,
        associationName: "personMeals",
        foreignKeyNames: ["personId"]
    }));
    et.addProperty(new NavigationProperty({
        name: "dishes",
        entityTypeName: "Dish",
        isScalar: false,
        associationName: "mealDishes",
    }));
    metadataStore.addEntityType(et);

    et = new EntityType({
        shortName: "Dish",
        namespace: "Sample_WebApi.Models"
    });
    et.addProperty(new DataProperty({
        name: "dishId",
        dataType: DataType.Int32,
        isNullable: false,
        isPartOfKey: true,
    }));
    et.addProperty(new DataProperty({
        name: "foodName",
        dataType: DataType.String,
        isNullable: false,
    }));
    et.addProperty(new DataProperty({
        name: "servingSize",
        dataType: DataType.Double,
        isNullable: false,
    }));
    et.addProperty(new NavigationProperty({
        name: "food",
        entityTypeName: "Food",
        isScalar: true,
        associationName: "DishFood",
        foreignKeyNames: ["foodName"]
    }));
    metadataStore.addEntityType(et);

    et = new EntityType({
        shortName: "Food",
        namespace: "Sample_WebApi.Models"
    });
    et.addProperty(new DataProperty({
        name: "foodName",
        dataType: DataType.String,
        isNullable: false,
        isPartOfKey: true,
    }));
    et.addProperty(new DataProperty({
        name: "calories",
        dataType: DataType.Int32,
        isNullable: false,
    }));
    metadataStore.addEntityType(et);
}
Bid answered 28/11, 2012 at 16:55 Comment(6)
I'd love to see an example on the Breeze sample site that shows how to hook up Breeze with "any" http web service.Mcgruter
That's a great example. Thank you. I assume the property names need to correlate with the property names in the C# model. And the namespace is the C# Model namespace? If I have generic repositories that have Get functions with all the odata params, I could probably just redirect the odata filter$, expand$ etc params to the repos' get method in the ODataActionFilter and return the resultant IQueryable which would match the client side data model that I would have to code - correct? This way I would piggy back my already exiting IRepo infrastructure instead of using IQueryables directly?Natality
Jay - do you happen know the answer to my question 3). I am basically looking for a breeze specific answer to role based overpost security/protection. Possibly with slightly thinner/ticker DTO object variations of the Model class. How involved would it be to create thinner (overpost protected) variations of Put/Post. Does new plumbing need to be made both on the server and client side? I am confused here because it seems most of breeze's benefit is the client side auto-implementation of the server-side meta-model. And DTOs wouldn't be part of that, so they'd have to be hand coded, right?Natality
@Natality Therefore I would not return a DTO from a WebApi controller just a ViewModel and that ViewModel has the input validation attributes. The DTO is just returned from the Service.Splenius
What breeze files need to be loaded for this to work? I get DataService is not defined same for new EntityType. I loaded q.js and breeze.debug.js . I must not be loading all the required files for this approachDiuretic
You should not need to load anything other than q and breeze.debug. Can you post the code you are having issues with as a separate SO question?Bid
B
2

1 You can configure metadata on the client. To turn off server metadata try this:

config.initializeAdapterInstances(
    new DataService({ 
        serviceName: "yourServiceNameHere",
        hasServerMetadata: false }));

2 Please look at the Breeze docs and api. Start here EntityType and here Extending Entities

Bentwood answered 28/11, 2012 at 15:36 Comment(2)
What breeze files need to be loaded for this to work? I get DataService is not defined same for new EntityType. I loaded q.js and breeze.debug.js . I must not be loading all the required files for this approach.Diuretic
Breeze objects reside in the breeze namespace. Please verify that you are referencing breeze.DataService and breeze.EntityType in your code.Bentwood
B
2

Per question 3: There are several possible approaches to this.

The first is that you can return objects that are not 'entities' to the client and these can be of virtually any shape. So you can determine what properties to include or exclude from them. Basically any object returned from the server for which matching client side metadata cannot be found will be returned as an anon json object. Note that these anon objects will not be wrapped by any binding library, i.e. ko, backbone, angular etc, and these objects will not be added to the entityManager cache.

A 2nd alternative is to use the json.net serialization interception points. (see the json.net help). This will allow you to conditionally suppress the serialization of selected properties. Be careful with this because if you try to resave any entities that have been returned to the client after having been "sanitized" you will need to restore these properties to their original values (on the server) before completing the save.

Per question 4: breeze is open source and available on github. You can use the source freely.

Per question 5: In the most recent versions of the breeze.webApi.dll we already refactored our EF specific code from our base webApi functionality for exactly this purpose. We haven't completed documenting this yet, but you can take a look at the "ContextProvider" and "EFContextProvider" classes in the Breeze.webApi project to see what another provider might look. We plan on showing a NoSQL provider for something like mongodb sometime in the near future. Please vote on the breeze user voice for any specific suggestions in this area.

Bid answered 29/11, 2012 at 23:34 Comment(4)
Thanks Jay - I have been using the 2nd alternative for my own hand coded WebApis so I am pretty familiar with it and like it a lot. I use an approach on the saving back part where I retrieve the entity by id first and then "overlay" the partial data on it before saving. Kind of like patch I guess.Natality
We are looking at some ways to make this process easier, mostly by providing apis to wrap the requery and fixup of a partial entity on the server. But any suggestions are greatly appreciated.Bid
If I had some suggestions how do you want me to pass them on to you? though SO?Natality
@Natality - You can post your suggestions here, but it might make more sense if you email breeze at ideablade dot com. Just reference this post in the email. (Btw, I work with Jay.) Thanks!Ecker

© 2022 - 2024 — McMap. All rights reserved.