Getting started with the Omniture APIs using Visual Studio 2010 (WCF)

by Sean Gubler on 3/3/11

If I had to pick one development platform as the most awkward for working with the Omniture web services it has to be Microsoft’s .NET. With Visual Studio 2005 it wasn’t too bad. You could simply leverage the WSE 3.0 extension and you were in business. But in Visual Studio 2010, WSE has been deprecated in favor of WCF, and unfortunately WCF doesn’t play nicely with the Password Digest authentication method used by the Omniture web services.

Microsoft declares… “B1102 WCF never emits Nonce and Created sub-elements of the UsernameToken.” http://msdn.microsoft.com/en-us/library/aa738565.aspx

This is a problem since the Omniture authentication requires both the Nonce and Created elements.

Luckily, talented Microsoft developers, like ASzego, have come to the rescue and have tweaked the WCF stack to solve the problem. See ASzego’s description of the problem and his solution here. http://blogs.msdn.com/b/aszego/archive/2010/06/24/usernametoken-profile-...

I’ve taken this code and packaged it up into a DLL file. I’ve also generated a second DLL file that contains the code produced from .NETs digestion of the Omniture WSDL. This code also needed a bit of tweaking which I won’t go into here. Both of these DLL files have been added to the code gallery here. http://developer.omniture.com/en_US/gallery/using-the-apis-with-wcf-dlls

What we have below is a getting started guide for putting together a quick VS2010 (C#) project that utilizes these two DLL files to make a successful request with the Omniture APIs.

Step 1: Create new Console application

Step 2: Copy the UsernameTokenLibrary.dll and OmnitureAPI.dll into the project. See DLLs.

Step 3: Add each dll file as a reference.

Step 4: Add “System.ServiceModel” as a reference under the “.NET” tab.

Step 5: Add the following code into the Main method…

OmnitureWebServicePortTypeClient client =
OmnitureWebServicePortTypeClient.getClient("[api username]", "[api secret]", "https://api.omniture.com/admin/1.3/");
int tokenCount = client.CompanyGetTokenCount();
Console.WriteLine(tokenCount);
Console.ReadLine(); //this is just to pause and observe the result when debugging

Step 6: Replace the first to arguments to the “getClient” method with your actual API username and API secret. Also, the third (endpoint) parameter may need to be adjusted based on which data center your account is tied to.

Step 7: Add the following “using” statements to the top of the file…

using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using Microsoft.ServiceModel.Samples.CustomToken;
using Adobe.OmnitureAPI;

Step 8: Run the application – observe the token count in the console window.

Finally, I must admit that I have very little experience with .NET and Visual Studio. The time I have spent is only due to the several desperate pleas I’ve seen for help in this area. If you have a better solution for using the Omniture APIs in VS 2010 I would love to hear it.

Please post your feedback.

Thanks,

Sean

Thanks for posting this. I implemented your solution and I am getting an error on the CompanyGetTokenCount method call: "Element 'faultstring' with namespace name '' was not found. Line 6, position 117." System.Exception {System.Xml.XmlException} Any idea how I can resolve this? Thanks.

Hi skruger, Unfortunately the exception you are seeing isn't revealing the real issue. I'm guessing that one of more of the parameters that you are specifying for the "getClient" call is incorrect. One way to see the actual SOAP fault that is being returned is to direct your requests through a packet monitoring program (like Charles) with some proxy settings. This allows you to see the actual SOAP messages going back and forth. I did this using the following three steps... 1- add the proxy settings in your application config file 2- handle the Certificate validation issue with a line of code in the top of your main method like this... System.Net.ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(customXertificateValidation); 3- the above line of code needs this method defined for your class... public static bool customXertificateValidation(object sender, System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors error) { return true; } By doing the above I was able to look in my Charles application and see that the actual faultString was "Invalid login." (i gave my app some invalid credentials to force this error). If you do the same you should be able to see what the real problem is. BTW - if anyone has an easier way to see the actual requests going across the wire I'd love to know about it. Hope that helps. -Sean

Hi Sean,greate help ! By the way , is possible i can donwload the full souce for this two library ? Thanks.

The source for these libraries is now available with the DLLs. http://developer.omniture.com/en_US/gallery/using-the-apis-with-wcf-dlls

Hi Sgubler, Do you have any experience with connecting to Omniture APIs using Business Objects? We want to connect Omniture to our Data Warehouse and would love some advice. http://developer.omniture.com/en_US/forum/partner-apis/how-to-extract-da...

Sorry Meghan. I have no experience with this Business Objects, however if you don't mind I'd like to reach out to you directly and ask a few questions about your use case because we are interested in making the Online Marketing Suite data easy to work with using the popular data integration platforms. -Sean

Hi Sean, i only get one file from link "src_code_OmnitureAPI.zip " . Is it something wrong ? Thanks

You need two DLL files. Both can be found here as separate downloads. http://developer.omniture.com/en_US/gallery/using-the-apis-with-wcf-dlls The .zip files contain the source code for these DLLs. The src_code_OmnitureAPI.zip only contains a single file. The other source code for the UsernameTokenLibrary.dll file is in a separate zip file.

You legend! I spent hours trying to get this working and got nowhere. Thanks!

Hi Sean, i follow your solution and get error too, can you please give me some advise. Attach is my "Program.cs" Here is the error details:


Attachments: to download.

This was a real time saver. Thanks

It work fine! Thanks sgubler then i have a question , i create a reportDescription like this : reportDescription description = new reportDescription (); description.dateFrom = "2011-07-10"; description.dateTo = "2011-07-16"; description.elements = new reportDefinitionElement [2] { new reportDefinitionElement(){ id="searchEngineKeyword", classification="searchEngine", top=100 }, new reportDefinitionElement(){ id="searchEngineKeyword", top=100 } }; description.metrics = new reportDefinitionMetric [1] { new reportDefinitionMetric(){ id="visits" } }; description.reportSuiteID = report.rsid; description.sortBy = "visits"; I want breakdown by search keyword , but i got the status is failed and the error code is '5024' , message is 'Invalid element' Am i wrong ? or i need setup some thing in my report suite ? Thanks sgubler.

Polomak - try doing your elements like this, first element id should be "searchEngine" and no "classification" needed... description.elements = new reportDefinitionElement [2] { new reportDefinitionElement(){ id="searchEngine", top=100 }, new reportDefinitionElement(){ id="searchEngineKeyword", top=100 } };

Great! But when i try description.elements = new reportDefinitionElement [1] { new reportDefinitionElement(){ id="searchEngine", top=100 } }; searchEngine only return 8 results, try description.elements = new reportDefinitionElement [1] { new reportDefinitionElement(){ id="searchEngineKeyword", top=100 } }; searchEngineKeyword only then return 51 result , but when i try both like your suggestion then return 0 result. I try was success on Omniture website Element "searchEngine" then breakdown by "searchEngineKeyword". Do you have any suggestion,sgubler ? Did i miss some thing ? or i can send you detail by email ? Thanks reply.

Polomak - you'll want to reach out to the SiteCatalyst Account Manager for your organization and have them check that the appropriate Traffic Sources Sub-relations are enabled for your report suite. I'm guessing they are not which would explain the results you are seeing. -Sean

Hi,sgubler you are so enthusiastic! I am the pre-sale analysis man for my organization and responsible for assess the integration between our system and Omniture SiteCatalyst. When i test the Web service Enterprise API through the sanbox and i have two questions as below : 1. Can we set up a web service user account that only can access few report suite? report element : searchEngineKeyword,searchEngine, eVar# report metric : visits,averageTimeSpentOnSite, Single Access,Entries. 2. Bounce Rate =Single Access/Entries , so we can get the avg time on site and bounce rate just from SiteCatalyst now ? We need to know these results before we decide to use Omniture service. Since we can not get the confirm from our consultant. I am really appreciate any assistance you can provide us on this, Many thanks.

Hi Chris.Lee - since it doesn't really relate directly to this post and since it is much easier to format messages in the "Forum" area of this site, could you please post these questions in the "Forum" area? I (or others) should be able to better answer them there.

Hi, Has anyone got this working with a larger number of rows? How did you make it work? When I increase intResultsToGet to, say, 1000 I get this error "The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element". As the Binding class (in the getClient method in Reference.cs) has no MaxReceivedMessageSize property I have tried substituting it for BasicHttpBinding but can't get that to authenticate with the API. Great work sgubler, this has been really helpful so far. Nick

Nick... thanks for the feedback. This is another one where I would recommend starting a forum thread with more details on the issue. Even share some of the key parts of your code. This will improve your chance of getting the help you need.

Hi Nick ,Please try add these code in "BingHelper" below this line HttpsTransportBindingElement httpsTransport = new HttpsTransportBindingElement (); //Set the MaxReceivedMessageSize httpsTransport.MaxBufferPoolSize = int.MaxValue; httpsTransport.MaxBufferSize = int.MaxValue; httpsTransport.MaxReceivedMessageSize = int.MaxValue;

Thank you Chris, you were spot on. I was debugging against the compiled DLL. It was my inexperience with using someone else's libraries showing through, once I reverted to the source I changed the method as described.

Hi, i try to use Omniture wsdl with WCF and VS2010. The link for using wcf is really usefull, but i found some problems... I download wsdl from web , because ( i think ) wsdl used in https://developer.omniture.com/en_US/gallery/using-the-apis-with-wcf-dll... seems to be different and problem start : i try to convert wsdl with vs tool , svcutil.exe and also with wsdl.exe, but with no success, i always get rpc error. Analizing the output i saw this warning [// CODEGEN: Generating message contract since the wrapper name CodeManager.DeleteCodeArchive) of message CodeManager.DeleteCodeArchiveRequest does not match the default value (CodeManagerDeleteCodeArchive)] for all entries. So i try to modify the wsdl to bypass this conversion problem and it works, i also add some line of code to use it throught proxy that requires authentication, but now i have a problem with buffer size , like Whiteleyn. I try to modify settings in app.config (maxReceivedMessageSize ecc.... ), but when i try to retrive data from DataWarehouseGet.GeportData (wsdl entry) always receive error about [ "The maximum message size quota for incoming messages (65536)......] . Do anyone have some suggestion ? Thank you !

Hi, excuse me, i read with attention Chris.Lee answer about buffer problem, and your snippet work , great, thank you. But i have another problem, the same that i got same time ago using old reference method ( wsdl.exe instead of wcf ) After send DataWarehouse.GetReportData, the program tries to parse response and return this error : The specified type was not recognized: name='data_warehouse_report_row', namespace='http://www.omniture.com/', at . If you have some advice , please let me know. thank you

Chris, I followed your advice in modifying the three properties of httpsTransport in BindingHelper.cs. Unfortunately, I am now getting an error that the SOAP response can't be deserialized when calling the ReportSuiteGetSettings method. Has anyone else run into this? Thanks Matt

Hi Sean , I have Followed the Instruction which is given above but while running my programme i met the exception below Exception: There was no endpoint listening at https://api.omniture.com/admin/1.2/ that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. My code: OmnitureWebServicePortTypeClient client = OmnitureWebServicePortTypeClient.getClient("username", "secret", "https://api.omniture.com/admin/1.2/"); int tokenCount = client.CompanyGetTokenCount(); Console.WriteLine(tokenCount); Console.ReadLine(); can you help me to resolve this issue. Thanks: Suresh

Hi Suresh, you can use fiddler (or similar ) to inspect your request and see if someting is wrong ( and also post the request to check it )

Hi Matt , I very sure this is will be another exception. Sorry I don't know the problem much without any details ,but i suggest you try to modify the encoding setting in BindingHelper.cs "TextMessageEncodingBindingElement textBindingElement = new TextMessageEncodingBindingElement ( MessageVersion.Soap11, new UTF8Encoding ( false, false ) );" WCF is very powerful . You can extend the IClientMessageFormatter,IDispatchMessageFormatter,MessageEncoder,EndpointBehavior...so on .That will very convenient on value monitor and debug . I suggest starting a forum thread to chat about this library.

Hello, I have tried using this post to create application and to request omniture API but its not working for me. the build gets done successfully but after that I get following error. "Could not load file or assembly 'OmnitureAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified." Please help me with this issue.

I just made a very minor update to this post so that it is current with the new 1.3 version of the API.

Hi sgubler, I have been creating an application to consume the Omniture API and I have been getting the same error as the first comment. After using a packet monitoring program I received the error "Could not establish trust relationship for the SSL/TLS secure channel with authority 'api.omniture.com'." Along with this the certificate validation method receives the status information as "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider."

My guess it has something to with my credentials however, when I look into the marketing suite portal the username and shared secret is correct. Am I missing something is setting up something?

Last sentence sounded horrible, " Am I missing something or did I set up something wrong?" ;)

Hi guys,

I know the subject might be a bit old but I just run into the same problem as suresh because of our internal proxy server.

I found a work around that seems to work, after decompiling the OmnitureAPI DLL, I have copied the code that creates and returns the client object, but I have added one parameter to the HttpsTransportBindingElement object.

I have attached my helper class so you guys can test it.


Attachments: to download.

Hi,

we are upgrading from SQL 2005 to 2012 and trying to convert my API calls to WCF. i have registered both dll's to GAC using strong name (adding it as reference was giving me error for some reason) and i can even see using gacutil -v that they are strongly named yet i am getting error on "UsernameTokenLibrary" complaining that it not strongly named. any ides?

below is the error that i am getting

"Could not load file or assembly 'UsernameTokenLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. A strongly-named assembly is required. (Exception from HRESULT: 0x80131044)"

i have windows 7 64 bit installed and using .NET framework 4

any ides how i can resolve this issue?

also forgot to mention that i am using VS 2010 (also called SQL server data tools)

hi,I want to get an hourly report about half year,it seems stack overflow.error is looks like below,looking forward to your help.
The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.

Use the following:
var httpsTransportBindingElement = new HttpsTransportBindingElement
{
UseDefaultWebProxy = false,
MaxReceivedMessageSize = 2147483647
};

Or use this DLL instead:
https://github.com/Sn3b/Omniture-API

1) Sean you rock
2) For those who are having trouble
-I highly recommend leaving charles open. I was able to get a better error message.. "invalid login"
-It turns out my login was fine but my endpoint was not! I opened the wsdl in notepad++ and searched for "1.3" and found my end is "https://api2.omniture.com/admin/1.3/" instead of "https://omniture.com/admin/1.3/"
-This made all the difference!! Now it works.

Hope that helps someone.

Sean,

Thanks for this, you've saved me a lot of frustration with getting this to work for a BI project we're starting to work on.

I do have one problem holding me back still though - it appears that specifying the rd.segment_id doesn't have an effect on the returned data from sc:

        // Define the report
        reportDescription rd = new reportDescription();
        rd.reportSuiteID = "tasovereignprod";

        rd.date = "2013-4-1";

        rd.metrics = new reportDefinitionMetric[3];
        rd.metrics[0] = new reportDefinitionMetric();
        rd.metrics[0].id = "visitors";
        rd.metrics[1] = new reportDefinitionMetric();
        rd.metrics[1].id = "pageviews";
        rd.metrics[2] = new reportDefinitionMetric();
        rd.metrics[2].id = "visits";

        rd.elements = new reportDefinitionElement[1];
        rd.elements[0] = new reportDefinitionElement();
        rd.elements[0].id = "evar6";
        rd.locale = reportDefinitionLocale.en_US;

        // Restrict to "Exclude US Direct Entry Visitors" segment
        rd.segment_id = "dw:209211";

Whatever I specify for the segment id (as returned from the API explorer), the results are the same and the segment is not applied to the report.

Anyone have any ideas? It's driving me mental.

Hi,

I am new to Omniture and have been assigned to create a client that we can somehow schedule to to send request to Omniture Datawarehouse to run the report and FTP the results to us. I am trying to figure out how to do this using C# and also wondering the reason behind using WCF. I was thinking of creating a console application that will send the request and also setup a SQL Agent job to run the console application once a week.

Your help in understanding the role of WCF and also getting started with console application will be really appreciated.

Thanks
Syed Zaidi

Following up on the first comment for the error "Element 'faultstring' with namespace name '' was not found". Why doesn't the API library throw an exception with the actual faulstring message? It sounds more like the library doesn't know how to handle error responses from the server. With automated processes we need to be able to log the specific error messages. Right now it appears the only way to get the real error message is to open up Fiddler and recreate the issue to monitor the traffic going back and forth to capture the server response.

@SyedZaidi - that is exactly what I'm going to be doing as well.

Did you get your project up and running and if so did you follow the technique laid out above by Sean?

I'm also wondering if I should now be using the 1.4 version of the API?

Thanks for any info!
Jason

Must be logged in to comment. or register now to comment!