breeze-client - any way to consume metadata from Web API? - breeze

Hi I created a method on my Web API Controller that successfully returns the metadata as string. I am just wondering if there is a clever way of generating entities at runtime instead of generating entities in TS client side beforehand?
[HttpGet]
public string Metadata()
{
return this.dataContext.Metadata();
}

The point of generating the TypeScript entities beforehand is so that you have types and intellisense to help you write your code correctly.
But of course the EntityManager can create entities on the fly from the metadata; you just need to know the name of the EntityType:
let cust = manager.createEntity("Customer");
And you can query entities from the server without pre-generated classes:
const query = new EntityQuery('Customers').where('lastName', 'startsWith', 'C');
manager.executeQuery(query).then(qr => {
let customers = qr.results;
// do something with customers...
});
In the early days of Breeze, we always loaded the metadata from the server on-the-fly, usually as the app was starting up.
These days, I code in TypeScript, and I find it very helpful to have the metadata and classes pre-generated.

Figured it out. The above method is needed or at least one called Metadata of type HTTP GET. the data service in breeze-client needs to have the property hasServerMetadata to false and the magic happens.

Related

Umbraco Forms - Export Data to CSV via code (not UI)

I'm trying to export Umbraco Forms data to CSV, in the exact format generated when you export from the Entries table UI, and I'm trying to do this strictly from code. End result is I would like to run as a task to export data daily or every few hours, and save that .csv file to a folder on the server. This would be for bulk importing into other systems, and a Forms Workflow won't work in this case.
My original approach was to try and do this in SQL, but Forms data would be difficult to work with since it's a in a mix of JSON and native SQL data. I'm not running SQL Server 2016 so no JSON support.
I've been searching through the Forms API and found a few things that might help, but can't seem to find what I need. So far I've tried:
Umbraco.Forms.Data.Storage.RecordStorage.GetAllRecords()
This gets the records, but unsure where to get the field names. I don't even see them in the UF tables. I can generate JSON output via GenerateRecordDataAsJson() but only get Guids for field names.
I've tried looping through the above Record collection and manually working with individual items, and I've tried the RecordStorage.BuildRecord() method hoping that would assemble the data, but no luck there either.
You have to get the field names using the API. When Forms was still Contour, EVERYTHING was in the database, making it easy(ish) to query stuff like this.
I think you need to use FormStorage to get the details of the form and you should be able to get the fields from that.
Thought I'd share an example for Umbraco 8 and Forms 8.4.1 since I just ran into this same requirement recently.
public class ExportController : UmbracoApiController
{
IRecordReaderService RecordReaderService;
public ExportController(
IRecordReaderService recordReaderService)
{
RecordReaderService = recordReaderService;
}
[HttpGet]
public void Export()
{
var formId = new System.Guid("f9ea767a-0e4e-4c90-85f1-53ef42c60793");
var pageSize = 50;
var formResults = RecordReaderService.GetRecordsFromForm(formId, 1, pageSize);
foreach (var entry in formResults.Items)
{
var firstName = entry.ValueAsString("firstName"); // Use field alias
// Output data or other
}
}
}

use of expand in breeze when mapping to DTOs on the server

I have had to move queries off the main database in order to meet requirements for complex authorization - for example a user with a given authorization role can only view data for individuals in the same institution.
I am using the Breeze .net DocCode sample for guidance, and have copied the premise for the mapping of domain models to DTOs.
get { return ForCurrentUser(Context.Orders).Select(o => new Order {
OrderID = o.OrderID,
....
OrderDetails = o.OrderDetails.Select(od => new OrderDetail
{
ProductID = od.ProductID,
UnitPrice = od.UnitPrice
...
})
The problem is that which mapped properties to .include(entity framework method)/.expand (breeze method) is now a concern of the mapping function (for example, the above code will always return the OrderDetails collection, whether I want them or not). I would like to still only eagerly load/expand properties if the javascript client generated predicate has a .expand directive for that property.
Is this at all possible, or am I stuck with manually defining different mapping functions on the server, depending on what properties I want expanded? (I am happy to use tools such as automapper if that would solve or simplify the problem)
Thank you
You will need to use the ODataQueryOptions as a parameter to your controller method. This gives you the details of the query predicates in your server method, so that you can apply them as needed rather that having them applied automatically. This will let you expand, or not, based upon the query.
See this answer and this answer to see how it works.

OData Web API routing

I have a web API exposing ODATA from a SQL stored proc. I want to use a url like /odata/firmhierarchy(225) to pass 225 into a param for the stored proc. It just tells me that it can't find a matching resource. It hits the controller, just skips the method. Thoughts?
In webapiconfig
private static IEdmModel GenerateEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees");
builder.EntitySet<Employee>("FirmHierarchy");
return builder.GetEdmModel();
}
Context:
public virtual ObjectResult<Employee> sp_EmployeeHierarchy(Nullable<int> managerEmpID)
{
var managerEmpIDParameter = managerEmpID.HasValue ?
new SqlParameter("ManagerEmpID", managerEmpID) :
new SqlParameter("ManagerEmpID", 0);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<Employee>("sp_EmployeeHierarchy #ManagerEmpID", managerEmpIDParameter);
}
Only method in controller:
[Queryable]
public IQueryable<Employee> GetFirmHierarchy()
{
return db.sp_EmployeeHierarchy(225).AsQueryable();
//return SingleResult.Create(db.Employees.Where(employee => employee.EmpId == key));
}
This should work:
1.Write another method in your controller:
[EnableQuery]
public IQueryable<Employee> Get([FromODataUri] int key)
{
return db.sp_EmployeeHierarchy(key).AsQueryable();
}
Please note that [EnableQuery] is an attribute introduced in Web API for OData V4. If you are still using Web API for OData V1-3, use [Queryable] still.
2.Then you can send the request
GET /odata/firmhierarchy(225)
and get the employees.
I was able to make ODATA work for a table, when auto-generated from entity framework. However, that generation process didn't want to work for a complex type returned by a Table Valued Function (similar scenario to a SP), because it didn't seem to understand where the key was.
What I found was that I could however make it work. First, I check out this article. He sets things up a bit more manually, where his Get on a companyProcessingController ends up routing for id 3 as "http://localhost:10020/odata/companyProcessing(3)" .
This surprised me. My other generated classes set up the pattern that SomeEntity became SomeEntityController, with methods like GetSomeEntities, and a routing that seemed to me to match the method but dropping the word get. Therefore, dropping the entity name from the Get method name seemed different, but it worked. Proving that the path is actually matching the controller name, not the method name.
In this Case you configure the routing using the data type you're querying for, and the beginning of the controller name. Then the actual path utilizes the beginning of the controller name as well.
And then all of this just brings us essentially to the other posted solution, assuming your controller name is firmhierarchyController
So, now, making sense of this... Try going to http://localhost:55063/odata/$metadata , where your port may differ. You'll notice that ODATA exposes a DataType, which is accessed via a DataSet. When a client tries to query into ODATA, they are trying to query against the DataSet, getting items of the DataType.
The DataSet matching the controller name (less Controller), and the Get methods can indeed just be Get without further extension of the name - and otherwise in this scenario was giving me problems.

JSON-serialization of NHibernate entities using the builtin JsonResult in ASP.NET MVC yields circular dependency error

I'm trying to return a JSON list of stuff from my server via an ASP.NET MVC front layer:
var stuff = repo.GetStuff();
return Json(stuff);
However, instead of the expected JSON, I get an error message stating
A circular reference was detected while serializing an object of type 'System.Reflection.RuntimeModule'.
I think I've found where this happens, but to explain it I need a simple example domain model as follows:
I am (lazily?) loading a selection of documents from NHibernate, like so:
var session = getNHibernateSession();
var query = new NhQueryable<Document>(session.GetSessionImplementation());
var docs = query.ToList().AsEnumerable();
I then pass the documents to return a JsonResult in my controller:
return Json(docs, JsonRequestBehavior.AllowGet);
Now, when Json() serailizes the collection, it walks over the properties of a document, finds a person. It serializes that person, and finds a project. It serializes the project, and finds - that's right - the person again! Since I'm lazy loading, it can just keep walking for ever if nothing stops it, but it's stopped by a circular reference error.
I don't really need to go all these levels down (I'd be fine without loading the project in the first place) - can I somehow affect how Json() serializes this collection, to not go further than, say, 2 levels down? I've googled around a little, but most of what I find seems to be from people who decided to use a serializing library directly, rather than just using the built-in functionality in .NET MVC. (Note: The solution to this problem must be possible to apply specifically to this case, since I might want to get JSON lists of people, including projects, somewhere else in the application...)
If you are retrieving Json, you have a service api. You have to design the api besides the implementation. Does the page that will be using it need all those fields and collections? probably not. What about adding more properties for other features and services? They will start appear in all the requests.
What you need is to use a ViewModel or just an anonymous type with the desired structure:
var session = getNHibernateSession();
var query = new NhQueryable<Document>(session.GetSessionImplementation());
var docs = query.ToList();
var result = query.Select(x => new {
x.Id,
x.Name,
People = new { p.Id,
p.Name,
p.Title
}
});
return Json( result, JsonRequestBehavior.AllowGet);
This way you can control what is being rendered and how.
It's already been answered here.
Also, it's generally a bad idea to expose your domain entities like this. If it's for read-only purposes it might not be so bad, but if any of your action methods accept a domain entity, then a specifically formatted request can overwrite properties on your domain entity that you don't want to (such as your PK).
To preserve object references in JSON, add the following code to Application_Start method in the Global.asax file:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;

what is the best way to store a user filtered query params in a database table?

I have an ASP.NET MVC website. In my backend I have a table called People with the following columns:
ID
Name
Age
Location
... (a number of other cols)
I have a generic web page that uses model binding to query this data. Here is my controller action:
public ActionResult GetData(FilterParams filterParams)
{
return View(_dataAccess.Retrieve(filterParams.Name, filterParams.Age, filterParams.location, . . .)
}
which maps onto something like this:
http://www.mysite.com/MyController/GetData?Name=Bill .. .
The dataAccess layer simply checks each parameter to see if its populated to add to the db where clause. This works great.
I now want to be able to store a user's filtered queries and I am trying to figure out the best way to store a specific filter. As some of the filters only have one param in the queryString while others have 10+ fields in the filter I can't figure out the most elegant way to storing this query "filter info" into my database.
Options I can think of are:
Have a complete replicate of the table (with some extra cols) but call it PeopleFilterQueries and populate in each record a FilterName and put the value of the filter in each of field (Name, etc)
Store a table with just FilterName and a string where I store the actual querystring Name=Bill&Location=NewYork. This way I won't have to keep adding new columns if the filters change or grow.
What is the best practice for this situation?
If the purpose is to save a list of recently used filters, I would serialise the complete FilterParams object into an XML field/column after the model binding has occurred. By saving it into a XML field you're also giving yourself the flexibility to use XQuery and DML should the need arise at a later date for more performance focused querying of the information.
public ActionResult GetData(FilterParams filterParams)
{
// Peform action to get the information from your data access layer here
var someData = _dataAccess.Retrieve(filterParams.Name, filterParams.Age, filterParams.location, . . .);
// Save the search that was used to retrieve later here
_dataAccess.SaveFilter(filterParams);
return View(someData);
}
And then in your DataAccess Class you'll want to have two Methods, one for saving and one for retrieving the filters:
public void SaveFilter(FilterParams filterParams){
var ser = new System.Xml.Serialization.XmlSerializer(typeof(FilterParams));
using (var stream = new StringWriter())
{
// serialise to the stream
ser.Serialize(stream, filterParams);
}
//Add new database entry here, with a serialised string created from the FilterParams obj
someDBClass.SaveFilterToDB(stream.ToString());
}
Then when you want to retrieve a saved filter, perhaps by Id:
public FilterParams GetFilter(int filterId){
//Get the XML blob from your database as a string
string filter = someDBClass.GetFilterAsString(filterId);
var ser = new System.Xml.Serialization.XmlSerializer(typeof(FilterParams));
using (var sr = new StringReader(filterParams))
{
return (FilterParams)ser.Deserialize(sr);
}
}
Remember that your FilterParams class must have a default (i.e. parameterless) constructor, and you can use the [XmlIgnore] attribute to prevent properties from being serialised into the database should you wish.
public class FilterParams{
public string Name {get;set;}
public string Age {get;set;}
[XmlIgnore]
public string PropertyYouDontWantToSerialise {get;set;}
}
Note: The SaveFilter returns Void and there is no error handling for brevity.
Rather than storing the querystring, I would serialize the FilterParams object as JSON/XML and store the result in your database.
Here's a JSON Serializer I regularly use:
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
namespace Fabrik.Abstractions.Serialization
{
public class JsonSerializer : ISerializer<string>
{
public string Serialize<TObject>(TObject #object) {
var dc = new DataContractJsonSerializer(typeof(TObject));
using (var ms = new MemoryStream())
{
dc.WriteObject(ms, #object);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
public TObject Deserialize<TObject>(string serialized) {
var dc = new DataContractJsonSerializer(typeof(TObject));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(serialized)))
{
return (TObject)dc.ReadObject(ms);
}
}
}
}
You can then deserialize the object and pass it your data access code as per your example above.
You didn't mention about exact purpose of storing the filter.
If you insist to save filter into a database table, I would have following structure of the table.
FilterId
Field
FieldValue
An example table might be
FilterId Field FieldValue
1 Name Tom
1 Age 24
1 Location IL
3 Name Mike
...
The answer is much more simple than you are making it:
Essentially you should store the raw query in its own table and relate it to your People table. Don't bother storing individual filter options.
Decide on a value to store (2 options)
Store the URL Query String
This id be beneficial if you like open API-style apps, and want something you can pass nicely back and forth from the client to the server and re-use without transformation.
Serialize the Filter object as a string
This is a really nice approach if your purpose for storing these filters remains entirely server side, and you would like to keep the data closer to a class object.
Relate your People table to your Query Filters Table:
The best strategy here depends on what your intention and performance needs are. Some suggestions below:
Simple filtering (ex. 2-3 filters, 3-4 options each)
Use Many-To-Many because the number of combinations suggests that the same filter combos will be used lots of times by lots of people.
Complex filtering
Use One-To-Many as there are so many possible individual queries, it less likely they are to be reused often enough to make the extra-normalization and performance hit worth your while.
There are certainly other options but they would depend on more detailed nuances of your application. The suggestions above would work nicely if you are say, trying to keep track of "recent queries" for a user, or "user favorite" filtering options...
Personal opinion
Without knowing much more about your app, I would say (1) store the query string, and (2) use OTM related tables... if and when your app shows a need for further performance profiling or issues with refactoring filter params, then come back... but chances are, it wont.
GL.
In my opinion the best way to save the "Filter" is to have some kind of json text string with each of the "columns names"
So you will have something in the db like
Table Filters
FilterId = 5 ; FilterParams = {'age' : '>18' , ...
Json will provide a lot of capabilities, like the use of age as an array to have more than one filter to the same "column", etc.
Also json is some kind of standard, so you can use this "filters" with other db some day or to just "display" the filter or edit it in a web form. If you save the Query you will be attached to it.
Well, hope it helps!
Assuming that a nosql/object database such as Berkeley DB is out of the question, I would definitely go with option 1. Sooner or later you'll find the following requirements or others coming up:
Allow people to save their filters, label, tag, search and share them via bookmarks, tweets or whatever.
Change what a parameter means or what it does, which will require you to version your filters for backward compatibility.
Provide auto-complete functions over filters, possibly using a user's filter history to inform the auto-complete.
The above will be somewhat harder to satisfy if you do any kind of binary/string serialization where you'll need to parse the result and then process them.
If you can use a NoSql DB, then you'll get all the benefits of a sql store plus be able to model the 'arbitrary number of key/value pairs' very well.
Have thought about using Profiles. This is a build in mechanism to store user specific info. From your description of your problem its seems a fit.
Profiles In ASP.NET 2.0
I have to admit that M$ implementation is a bit dated but there is essentially nothing wrong with the approach. If you wanted to roll your own, there's quite a bit of good thinking in their API.

Resources