ReportDefinitionService doesnt work

331 views
Skip to first unread message

Michael D

unread,
Mar 6, 2015, 5:40:40 AM3/6/15
to adwor...@googlegroups.com
Hey People,

im trying to get a report and im sending this request:

POST https://adwords.google.com/api/adwords/cm/v201406/ReportDefinitionService HTTP/1.1
User-Agent: Mono Web Services Client Protocol 4.0.50524.0
Authorization: Bearer ya29.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SOAPAction: ""
Content-Type: text/xml; charset=utf-8
Content-Length: 691
Host: adwords.google.com

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<RequestHeader xmlns="https://adwords.google.com/api/adwords/cm/v201406">
<clientCustomerId>xxx-xxx-xxxx</clientCustomerId>
<developerToken>XXXXXXXXXXXXXXXXXXXX</developerToken>
<userAgent>UserAgent</userAgent>

</RequestHeader>
</soap:Header>
<soap:Body>
<getReportFields xmlns="https://adwords.google.com/api/adwords/cm/v201406">
<reportType>CAMPAIGN_PERFORMANCE_REPORT</reportType>
<reportTypeSpecified>true</reportTypeSpecified>
</getReportFields>
</soap:Body>
</soap:Envelope>

if reportTypeSpecified is true im gettin the Error:

soap:Fault faultcode
 Unmarshalling Error: cvc-complex-type.2.4.d: Invalid content was found starting with element 'reportTypeSpecified'. No child element is expected at this point.

if it is false:
Unmarshalling Error: cvc-complex-type.2.4.a: Invalid content was found starting with element 'reportTypeSpecified'. One of '{"https://adwords.google.com/api/adwords/cm/v201406":reportType}' is expected.

Does anyone know what I have to change to get some Reports?

Thank you

Josh Radcliff (AdWords API Team)

unread,
Mar 6, 2015, 9:30:12 AM3/6/15
to adwor...@googlegroups.com
Hi,

The reportTypeSpecified field you mentioned is not part of the getReportFields spec (see the service XSD here). If you remove that field from your request, it should work.

Thanks,
Josh, AdWords API Team

Michael D

unread,
Mar 8, 2015, 11:56:25 AM3/8/15
to adwor...@googlegroups.com
Hi Josh,

im using this Web Service:  https://adwords.google.com/api/adwords/cm/v201409/ReportDefinitionService?wsdl

First get the ReportDefinitionService:
            var client = new ReportDefinitionService.ReportDefinitionService();

set the ReportDefinitionReportType:
           const ReportDefinitionReportType reportType = ReportDefinitionReportType.ACCOUNT_PERFORMANCE_REPORT;

But when im trying to get ReportFields with getReportFields or getReportFieldsAsync like below
client.getReportFields(reportType,false);
client.getReportFieldsAsync(ReportDefinitionReportType.KEYWORDS_PERFORMANCE_REPORT, false);

both given Methods requires ReportDefinitionReportType and reportTypeSpecified.

But if reportTypeSpecified is not part of the getReportFields then why they need it?

Josh Radcliff (AdWords API Team)

unread,
Mar 8, 2015, 11:02:36 PM3/8/15
to adwor...@googlegroups.com
Hi,

Are you using one of our client libraries? If so, please look for the GetReportFields example in the reporting examples folder. For example, the C# example is here.

As the WSDL you mentioned shows, there is no reportTypeSpecified argument to GetReportFields, so I'm not quite clear on where you are seeing this field.

Thanks,
Josh, AdWords API Team

Michael D

unread,
Mar 9, 2015, 7:24:05 AM3/9/15
to adwor...@googlegroups.com

Hi Josh,

Im adding the WebReference like I mentioned.

When looking into the Reference the Constructor also shows that reportTypeSpecified is needed.

Thanks

Michael

Michael D

unread,
Mar 9, 2015, 9:27:18 AM3/9/15
to adwor...@googlegroups.com
Hi,

seems like .NET svcutil creates these specified Arguments by default.
Modify the Constructor in the Reference solved it.

Thanks

Michael

Anash P. Oommen (AdWords API Team)

unread,
Mar 9, 2015, 9:28:55 AM3/9/15
to adwor...@googlegroups.com
Hi Michael,

My best guess is that Mono is not handling System.Xml.Serialization.XmlIgnoreAttribute() on a method parameter correctly. Could you please consider using the AdWords API .NET library instead?

If you want a longer explanation, then

- reportTypeSpecified is generated by Mono because the wsdl definition for getReportFields in ReportDefinitionService.wsdl looks like this:

<element name="getReportFields">
 
<complexType>
   
<sequence>
     
<element maxOccurs="1" minOccurs="0" name="reportType"
         
type="tns:ReportDefinition.ReportType">
     
</element>
   
</sequence>
 
</complexType>
</element>

ReportDefinition.ReportType is an enum (which is non-nullable in .NET), but minOccurs=0, maxOccurs=1 in the wsdl suggests that the reportType parameter may be set to null. reportTypeSpecified flag is a hack by the .NET framework to tell the serialization framework whether or not to treat the reportType node as null. (i.e. if reportTypeSpecified == false, then ignore the value on reportType and treat it as a null)

- However, since reportTypeSpecified is a hack parameter introduced by .NET code generator (and not part of wsdl itself) it should decorate the reportTypeSpecified parameter with an [System.Xml.Serialization.XmlIgnoreAttribute()] to ensure that reportTypeSpecified itself is not part of the SOAP envelope.

- You can see that Mono does this for getReportFields method, but not for getReportFieldsAsync method.
- From your SOAP logs, you can also see that Mono's XML serialization framework doesn't respect [System.Xml.Serialization.XmlIgnoreAttribute()] on a method parameter.

The fix would be to patch the generated code to remove reportTypeSpecified parameter from the getReportFields method.

Cheers,
Anash P. Oommen,
AdWords API Advisor.

Michael D

unread,
Mar 10, 2015, 7:23:02 AM3/10/15
to adwor...@googlegroups.com
Hi Anash,

im in a portable class libary, the AdWords API .NET libary does not work for me.

Yes you are right. Mono cant handle XmlIgnoreAttribute() correctly.

Patching the generated code works fine for me now.

Im getting the ReportFields now. But no values for example for clicks or impressions. 

Do I have to combine the getReportFields with something to get the values e.g. for all Campaigns?

Anash P. Oommen (AdWords API Team)

unread,
Mar 11, 2015, 4:03:27 PM3/11/15
to adwor...@googlegroups.com
Hi Michael,

You have to use AdWords API reports to get the reporting data. Reporting API is not a SOAP API, it is a plain URL endpoint that takes a POST request. You can find the details here: https://developers.google.com/adwords/api/docs/guides/reporting

And if you are getReportFields to lookup fields, then you can probably skip that step, since the report columns don't change that frequently. The list of supported reports and their fields are documented on https://developers.google.com/adwords/api/docs/appendix/reports

Also, I remember reading that System.Web.Services is not part of Portable Class Libraries. What library are you using to make SOAP calls in your PCL compatible library?

Cheers,
Anash P. Oommen
AdWords API Advisor.

Michael D

unread,
Mar 13, 2015, 5:19:47 AM3/13/15
to adwor...@googlegroups.com
Hi Anash,

do you have a simple example for how some of these POST requests are looking like?

I have a Xamarin Project and im using System.Web.Services in the Android or iOS section of the code. Cant use it in shared code.

Thanks Michael

Michael D

unread,
Mar 13, 2015, 9:15:31 AM3/13/15
to adwor...@googlegroups.com
I always get this Error:
<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
<reportDownloadError>
<ApiError><type>ReportDownloadError.MISSING_PARAMETER</type>
<trigger>Missing report definition</trigger>
<fieldPath></fieldPath>
</ApiError>
</reportDownloadError>

This is the way im doing it:

 public string GetReport()
        {
            var client = new HttpClient();
            client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accesToken);
            client.DefaultRequestHeaders.Add("developerToken", developerToken);
            client.DefaultRequestHeaders.Add("clientCustomerId",clientCustomerId);

            var request = new HttpRequestMessage(HttpMethod.Post, baseAdressAdWords)
            {
                Content = content
            };
            var response = client.SendAsync(request).Result;
            var soapResponse = response.Content.ReadAsStringAsync().Result;
            var streamSoapResponse = response.Content.ReadAsStreamAsync().Result;

            return soapResponse ;
        }
        private string ConstructPostRequest()
        {
            return String.Format(@"<reportDefinition xmlns=""https://adwords.google.com/api/adwords/cm/v201409"">
                  <selector>
                    <fields>CampaignId</fields>
                    <fields>Id</fields>
                    <fields>Impressions</fields>
                    <fields>Clicks</fields>
                    <fields>Cost</fields>
                    <predicates>
                      <field>Status</field>
                      <operator>IN</operator>
                      <values>ENABLED</values>
                      <values>PAUSED</values>
                    </predicates>
                  </selector>
                  <reportName>Custom Adgroup Performance Report</reportName>
                  <reportType>ADGROUP_PERFORMANCE_REPORT</reportType>
                  <dateRangeType>LAST_7_DAYS</dateRangeType>
                  <downloadFormat>XML</downloadFormat>
                </reportDefinition>"
                );
Reply all
Reply to author
Forward
0 new messages