How do I filter with OData based on an inner array? - asp.net

So I created a controller using the mvc4 web api where the url (Get) “/api/things” return the following data:
<ArrayOfThing>
<Thing>
<Id>1</Id>
<Description>The Thing Desc</Description>
<Categories>
<Category><Id>1</Id></Category>
<Category><Id>2</Id></Category>
</Categories>
</Thing>
<Thing>
<Id>2</Id>
<Description>The Other Thing Desc</Description>
<Categories>
<Category><Id>1</Id></Category>
<Category><Id>3</Id></Category>
</Categories>
</Thing>
</ArrayOfThing>
*note that thing and categories has a many to many relationship
I know that if a need one “Thing” resource I should use a controller that matches the following route url (Get) “/api/things/{id}”.
But what if I want to get a subset of the data returned by the url (Get) “/api/things”. I tested the OData protocol modifying the controller to return an IQueryable and it work fine if I wanted to $filter on the properties of “Thing” like the Id or the Description. Unfortunately, I didn’t work out when I wanted to filter base on the Category, I believe is because Categories is an inner array.
So, what should I do to filter based on categories?

OData V3 supports Any/All operations, which you can filter by a collection property. For example, to filter things which contains Category(1), using following syntax:
/api/things/?$filter=Categories/any(category: category/Id eq 1)
If you are using ASP.net Web Api RTM bits, you can use odata package to support any/all. For more examples, you can check the queryable sample code: http://aspnet.codeplex.com/SourceControl/changeset/view/61dfed023e50#Samples%2fNet4%2fCS%2fWebApi%2fODataQueryableSample%2fProgram.cs

Related

BizTalk json encoder not using the correct type

I'm trying to send a quite simple JSON message from BizTalk.
{
"Value": 1
}
I set the type of the "Value" field to xs:int in my xml schema
<xs:element minOccurs="1" maxOccurs="1" name="Value" type="xs:int" />
But it keeps generating the wrong JSON message.
{
"Value": "1"
}
Not sure what I'm doing wrong here. Does anybody have some tips?
There can be multiple issues at work here.
Your XML payload is not going through a XML Dissasembler or Assembler before reaching the JSON Encoder, and hence the Message Type isn't set correctly, in which case it is not using the schema to determine the correct date types.
You have another earlier element in your schema with the same name but a different type. It will use the type from the first one for all elements with the same name. This was a bug in BizTalk 2013 R2, and I think it was still there in BizTalk 2016 and could cause some strange errors, especially if you had a Records (complex types) and Element (simple types) with the same name. e.g FIX: JSON encoder unable to handle XML schema with the same name for record and one of its elements in CU 7
Biztalk Embedded JSON Encoder has the ability to recognize schema of XML processed and should recognize xs:int value from schema and encoded without quotes.
But sometimes (as Sandro Pereira indicates even often) this encoder throws the error:
Reason: Value cannot be null.
Parameter name: key
That was my case. I had to use a custom JSON Encoder that recognizes XML datatype somehow.
My solution was:
Use this build of Newtonsoft.Json library that uses json:Type argument as indicator of XML tag datatype.
Create a custom JSON Encoder that uses the previous library
Create custom Complex Type in separate schema with targetNamespace = "http://james.newtonking.com/projects/json"
Note that attribute Type need to be Qualified
Import above schema in Your target schema using prefix json
Use this type as Data Structure Type and rename Your parameter.
Map this checking logical existance, to avoid putting argument without value or custom xslt tranform
Usefull sites:
Adding name to attribute

BizTalk WCF-WebHttp URI mapping problem with escaped variable

I am trying to use BizTak WCF-WebHttp adapter to send to Service Desk Plus CMDB API using Variable Mapping.
When trying using the browser, it works fine. Service Desk Plus CMDB API requires an URI like (strictly shortened for readability):
http://host.com/api/cmdb/ci?OPERATION_NAME=read&TECHNICIAN_KEY=Mykey&format=XML&INPUT_DATA=<?xml version='1.0'?>
<API>
<name>email#host.com</name>
</API>
I have used the URI http://host.com/api/cmdb/ci and URL Mapping.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<name>email#host.com</name>
</API>"/>
</BtsHttpUrlMapping>
This works fine, but I need a more dynamic approach. I tried using Variable Mapping, so I replaced the hard coded email address with a variable.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<name>{email}</name>
</API>"/>
</BtsHttpUrlMapping>
Trying to save the URL Mapping with the variable I get an error.
WCF-WebHttp Transport Properties
Error saving properties.
(System.InvalidOperationException) The UriTemplate
?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version='1.0'?><API><name>{email}</name></API>
is not valid; each portion of the query string must be of the form 'name=value', when value cannot be a compound segment. See the documentation for UriTemplate for more details.
If I try a variable that is not within the escaped XML string, like with the key, then it works fine.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY={key}&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<value>email#host.com</value>
</API>"/>
</BtsHttpUrlMapping>
My intention is to be able to use a variable within the escaped XML string. If that is not possible; I will have to turn to a dynamic adapter and Create the URI and URL mapping in an orchestration.
Did u understand why it said each portion of the query string must be of the form 'name=value? There are just a few ways to make UriTemplates work.
See how a UriTemplate works here. Here is an example that is valid:
weather/{state}/{city}?forecast={day}
So in your case you should make everything after INPUT_DATA= a variable. Which means the whole escaped XML string you were talking about.

Is there a REST API to get subfolders of the workspace in Tosca?

I am trying to build a UI based in Angular to retrieve all existing execution lists of Tosca. However, I could not find a REST API that can give the list of folders within a workspace in Tosca. Has anyone tried this route?
You can use the Search task on the projectto find all ExecutionLists.
Example:
{rest_url}/ToscaCommander/{workspace_name}/object/project/task/Search
as a post request with the xml payload:
<Parameters xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Parameter>
<Name>tqlString</Name>
<Type i:nil="true"/>
<Value>->SUBPARTS:TCFolder[Name=?"Execution"]=>SUBPARTS:ExecutionList</Value>
</Parameter>
</Parameters>
This will give you a list of object ids of the ExecustionLists contained in the Execution folder of the project. You can fetch the objects one by one with this request afterwards:
{rest_url}/ToscaCommander/{workspace_name}/object/{object_id}
Credits for this solution go to the development team of ToscaCommander - they provided it.
P.S.: as an answer for your comment:
Yes, there is a json equivalent of the body - but you do not need it. Anyway, here is the equivalent:
[{
"Name":"tqlString",
"Value":"->SUBPARTS:TCFolder[Name=?\"Execution\"]=>SUBPARTS:ExecutionList"
}]
If you want to get a json response (regardless of the request's payload's format) make sure your web.config sets AutomaticFormatSelectionEnabled to true (which should be the case). Then, in your requests, set the accept header accordingly:
Accept: application/json

Access the HTTP Response from xdmp:http-get()

Using MarkLogic to pull in data from a web service with xdmp:http-get() or xdmp:http-post(), I'd like to be able to check the headers that come back before I attempt to process the data. In DQ I can do this:
let $result := xdmp:http-get($query,$options) (: $query and $options are fine, I promise. :)
return $result
And the result I get back looks like this:
<v:results v:warning="more than one node">
<response>
<code>200</code>
<message>OK</message>
<headers>
<server>(actual server data was here)</server>
<date>Thu, 07 Jun 2012 16:53:24 GMT</date>
<content-type>application/xml;charset=UTF-8</content-type>
<content-length>2296</content-length>
<connection>close</connection>
</headers>
</response>
followed by the actual response. the problem is that I can't seem to XPath into this response node. If I change my return statement to return $result/response/code I get the empty sequence. If I could check that code to make sure I got a 200 back before attempting to process the actual data that came back it would be much better than using try-catch blocks to see if the data exists and is sane.
So, if anyone knows how to access those response codes I would love to see your solution.
For the record, I have tried xdmp:get-response-code(), but it doesn't take any parameters, so I don't don't know what response code it's looking at.
You're getting burned by two gotchas at once:
awareness of namespaces
awareness of document nodes
First, the namespace. The XML output of the http-get function is in a namespace as seen by the top-level element:
<response xmlns="xdmp:http-get">
To successfully access elements in that namespace, you need to declare a prefix in your query bound to the correct namespace, and then use that prefix in your XPath expressions. For example:
declare namespace h="xdmp:http-get";
//h:code
Now lets talk about document nodes. :-)
You're trying to access $result as if it is a document node containing an element, but in actuality, it is a sequence of two root nodes (so they're not siblings either). The first one (the one you're interested in here) is a parentless <response> element—not a document containing a <response> element.
This is a common gotcha: knowing when a document node is present or not. Document nodes are always invisible when serialized (hence the gotcha), and they're always present on documents stored in the database. However, when you just use a bare element constructor in XQuery (as the http-get implementation does), you construct not a document node but an element node without a document node parent.
For example, the following query will return the empty sequence, because it's trying to get the <foo> child of <foo>:
declare variable $foo := <foo>bar</foo>;
$foo/foo
On the other hand, the following does return <foo>, because it's getting the <foo> child of the document node (which has to be explicitly constructed, in XQuery):
$declare variable $doc := document{ <foo>bar</foo> };
$doc/foo
So you have to know how a given function's API is designed (whether it returns a document containing an element or just an element).
To solve your problem, don't try to access $result/h:response/h:code (which is trying to get the <response> child of <response>). Instead, access $result/h:code (or more precisely $result[1]/h:code, since <response> is the first of a sequence of two nodes returned by the http-get function).
For more information on document nodes, check out this blog article series: http://community.marklogic.com/blog/document-formats-part1

Getting the base URL for a property via Google Analytics API?

I'm working with the Google Analytics API, and am pulling a lot of data from it successfully. The accounts feed (https://www.google.com/analytics/feeds/accounts/default) returns a list of web properties connected to the account you're authorized for, in the following format (most actual values replaced, not sure how sensitive any of it is):
<entry gd:etag="W/"<charsblahblahblah>."" gd:kind="analytics#account">
<id>http://www.google.com/analytics/feeds/accounts/ga:########</id>
<updated>2011-08-04T12:01:33.467-07:00</updated>
<title>www.afifthofnothing.com</title>
<link rel="alternate" type="text/html" href="http://www.google.com/analytics"/>
<dxp:property name="ga:accountId" value="#####"/>
<dxp:property name="ga:accountName" value="My Sites"/>
<dxp:property name="ga:profileId" value="######"/>
<dxp:property name="ga:webPropertyId" value="UA-#####-#"/>
<dxp:property name="ga:currency" value="USD"/>
<dxp:property name="ga:timezone" value="America/Los_Angeles"/>
<dxp:tableId>ga:#######</dxp:tableId>
</entry>
I've previously been using the <title> element as the base URL for the property, which usually works because that's the default title that Google Analytics assigns to the property. But if a user edits this (I'm querying my end-users' accounts, so I don't have control there) to something like "A Fifth Of Nothing", then the Analytics API will dutifully return that as the title, leaving me with no way to find the base URL.
I've scoured the Analytics API documentation and googled around, searched SO, but don't see any way to get the base URL of a web property from Google Analytics. I've tried querying the id field via the OAuth Playground for more info, and it just gives me more errors, saying the last part has to be /default.
Is there a way to get the base URL for a user's properties from the data API? It seems like this would be something pretty basic. If not, I'll have to resort to trying the title, and if it's not URL-like just have the user enter it themselves, which is not very user-friendly, but is the only thing I can come up with at this point.
The strategy to use is to do a query against the ga:hostname dimension for ga:visits and sort descending. You typically can use this to reveal the host/base url.
I don't think there is such a property for the "base url" because technically you can put the google tracking code on multiple websites. And in this instance you would have multiple base url.
View Full Page URL In Reports
By default, the data in your reports includes only the Request URI and not the domain name:
URL of page: http://www.example.com/foldername/page.html
Request URI: /foldername/page.html
Domain name: www.example.com
If you'd like to see the domain name as well as the Request URI in your reports, create an Advanced filter for your view with the following settings:
Filter Type: Custom filter > Advanced
Field A: Hostname
Extract A: (.*)
Field B: Request URI
Extract B: (.*)
Output To: Request URI
Constructor: $A1$B1
Note that creating URL rewrite filters like the one described above can affect Analytics' ability to match your goals properly.
If you're using Analytics filters to rewrite your URLs, you need to make sure that your goal settings reflect these changes. Like all filters, URL-rewrite filters are applied to the raw data coming into your account, before goals are processed. As a result, your goal and funnel URLs should reflect the final, rewritten format of the URL. For example:
If your site's URL:
/directory/download/file.html
is rewritten by a filter to look like:
/download/file
then your goal should match
/download/file and not /directory/download/file.html

Resources