I'm trying to push an ecommerce transaction with minimal information
to analytics, following are two method implementation of it but none
seem to work. These methods are constructed by referring to the
documentation and code snippets on forums.
public static void pushToGoogleAnalytics(String analyticsCode, String
domain, String product_sku, String product) {
Map<String, String> params=new TreeMap<String, String>();
params.put("utmwv", 4+"");
params.put("utmn", new Random().nextInt(2147483647)+"");
params.put("utmhn", domain);
params.put("utmipc", product_sku);
params.put("utmipn", product);
params.put("utmtid", product_sku);
params.put("utmdt", product);
params.put("utmp", "/");
params.put("utmhn", domain);
params.put("utmac", analyticsCode);
params.put("utmcc", "__utma%3D999.999.999.999.999.1%3B");
try {
byte[] response = URLUtils.get(new URL("http://www.google-
analytics.com/__utm.gif"), params);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void pushToGoogleAnalytics(String analyticsCode, String
domain, String product_sku, String product) {
String var_utmac = analyticsCode;
String var_utmhn = domain; // domain
String var_utmn = random(1000000000,2147483647)+""; // random number
String var_cookie = random(10000000,99999999)+""; //random cookie
number
String var_random = random(1000000000,2147483647)+""; //number under
2147483647
String var_today = Utils.getNow().getTime()+"";
String var_uservar="-"; // no user-defined
String urchinUrl="http://www.google-analytics.com/__utm.gif?
utmwv=3&utmn="+var_utmn+"&utmipc="+product_sku+"&utmipn="+product
+"&utmtid="+product_sku+"&utmdt=test&utme=&utmcs=-&utmsr=-&utmsc=-
&utmul=-&utmje=0&utmfl=-&utmdt=-&utmhn="+var_utmhn+"&utmhid="+var_utmn
+"&utmac="+var_utmac+"&utmcc=__utma%3D"+var_cookie+"."+var_random
+"."+var_today+"."+var_today+"."+var_today+".2%3B%2B__utmz
%3D"+var_cookie+"."+var_today+".2.2.utmcsr%3D_SOURCE_%7Cutmccn
%3D_CAMPAIGN_%7Cutmcmd%3D_MEDIUM_%7Cutmctr%3D_KEYWORD_%7Cutmcct
%3D_CONTENT_%3B%2B__utmv%3D"+var_cookie+"."+var_uservar+"%3B";
// urchinUrl=urchinUrl.replace("&", "&");
byte[] response = URLUtils.readURL(urchinUrl);
System.err.println("google analytics push URL: "+urchinUrl);
}
Please have a look at this article I've recently published about pushing data to Google Analytics via Python.
Note that it gives you only the bare minimum and you can easily convert it to your favourite language. You'll need to add e-commerce related parameters though.
Related
I want get my run activity location data and use the data in my android app,so I use the Microsoft health cloud API. I can login by using my live ID, and I can read my activity data,include MapPoints, but I can`t get any GPS location information. ‘latitude’ and ‘longitude’ value is 0.
I have set the scope of oauth2.0 to "offline_access mshealth.ReadProfile mshealth.ReadActivityHistory mshealth.ReadActivityLocation mshealth.ReadDevices",but it still doesn't work.
I use android async httpclient to get data.
String msToken = "MSTOKEN...";
String profileUrl = ConstValue.getMSHealthURL(ConstValue.MS_API_HEALTH_URL_ACTIVITIES);
RequestParams params = new RequestParams();
params.add("activityIds","2519604437250480855");
params.add("activityIncludes","Details,MapPoints");
AsyncHttpClient client = new AsyncHttpClient(true, 80, 443);
msToken = String.format("bearer %s", msToken);
client.addHeader("Authorization",msToken);
Log.v("mstoken",msToken);
client.get(profileUrl,params, new TextHttpResponseHandler() {
#Override
public void onFailure(int i, Header[] headers, String s, Throwable throwable) {
}
#Override
public void onSuccess(int i, Header[] headers, String s) {
Log.v("activity",s);
}
});
Microsoft said they have been fix the bug,and I tested it,it's ok now.
I need to set a Custom Dimension from the server side, I am trying this request:
http://www.google-analytics.com/collect?&v=1&tid=UA-XXXXXXXX-X&cid=111111111.111111111&t=all&cd1=MyCustomDimension
In the "t" value I also try "event" and "pageview" but it doesn't work.
I created this class for do the request.
public static class GoogleAnalyticsServerSide
{
private static string googleURL = "http://www.google-analytics.com/collect";
private static string googleVersion = "1";
private static string googleTrackingID = "UA-XXXXXX-X";
private static string googleClientID = "111111111.11111111";
private static Dictionary<string, string> baseValues()
{
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("v", googleVersion); // Version.
data.Add("tid", googleTrackingID); // Tracking ID / Web property / Property ID.
data.Add("cid", googleClientID); // Anonymous Client ID.
return data;
}
public static void TrackEvent(string category, string action, string label)
{
Dictionary<string, string> postData = new Dictionary<string, string>();
postData = baseValues();
postData.Add("t", "event");
postData.Add("ec", category);
postData.Add("ea", action);
postData.Add("el", label);
Track(postData);
}
public static void TrackCustomDimension(string index, string value)
{
Dictionary<string, string> postData = new Dictionary<string, string>();
postData = baseValues();
postData.Add("t", "all");
postData.Add("cd" + index, value);
Track(postData);
}
private static void Track(Dictionary<string, string> postData)
{
try
{
var request = (HttpWebRequest)WebRequest.Create(googleURL);
request.Method = "POST";
var postDataString = postData
.Aggregate("", (data, next) => string.Format("{0}&{1}={2}", data, next.Key,
HttpUtility.UrlEncode(next.Value)))
.TrimEnd('&');
// set the Content-Length header to the correct value
request.ContentLength = Encoding.UTF8.GetByteCount(postDataString);
// write the request body to the request
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(postDataString);
}
try
{
var webResponse = (HttpWebResponse)request.GetResponse();
if (webResponse.StatusCode != HttpStatusCode.OK)
{
throw new HttpException((int)webResponse.StatusCode,
"Google Analytics tracking did not return OK 200");
}
}
catch (Exception ex)
{
}
}
catch (Exception e)
{
}
}
}
The class works well because if I use the TrackEvent method it works. I am not sure if I missing something in the post request of Custom Dimension.
Thanks in advance.
I'm not sure what you mean by "it doesn't work" because what you have looks fine to me.
Regardless, you should try using the Measurement Protocol Hit Builder to create and validate your hits prior to sending them, just to make sure all required fields are there.
If you want to validate your hits in code, you send your hits to the Measurement Protocol Validation Server to check their validity before sending them to Google Analytics. The hit builder actually uses this tool under the hood to validate the hits.
I am trying to integrate oauth authentication from an MVC 4 project to Microsoft (Live service). The followings lines in AuthConfig.cs have been uncommented:
OAuthWebSecurity.RegisterMicrosoftClient(
clientId: "XXX",
clientSecret: "XXX");
And, the app has been set up at https://manage.dev.live.com
Later, when OAuthWebSecurity.VerifyAuthentication is called, I get back the success status, but the email field is not in the returned data.
How can I request an email to be returned from VerifyAuthentication call issued again Microsoft account?
Thanks.
First, you should implement a 'MicrosoftScopedClient' class which implements 'IAuthenticationClient ' interface, and that should implement two methods of interface which is;
public class MicrosoftScopedClient : IAuthenticationClient
{
//Define following three keys in Web.Config file and use it in code, it will maintain code consistency.
private string clientId;
private string clientSecret;
private string scope;
private const string baseUrl = "https://login.live.com/oauth20_authorize.srf";
private const string tokenUrl = "https://login.live.com/oauth20_token.srf";
public void RequestAuthentication(HttpContextBase context, Uri returnUrl)
{
//Getting values of clientId, clientSecret and scope from Web.Config file
clientId=System.Configuration.ConfigurationManager.AppSettings["msClientId"].ToString();
clientSecret=System.Configuration.ConfigurationManager.AppSettings["msClientSecret"].ToString();
scope=System.Configuration.ConfigurationManager.AppSettings["msScope"].ToString();
string url = baseUrl + "?client_id=" + clientId + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString()) + "&scope=" + HttpUtility.UrlEncode(scope) + "&response_type=code";
//this will authenticate the user and register(only if user visited first time).
context.Response.Redirect(url);
}
public AuthenticationResult VerifyAuthentication(HttpContextBase context)
{
string code = context.Request.QueryString["code"];
string rawUrl = context.Request.Url.ToString();
//removing code portion
rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");
IDictionary<string, string> userData = GetUserData(code, rawUrl);
if (userData == null)
return new AuthenticationResult(false, ProviderName, null, null, null);
string id = userData["id"];
string username = userData["email"]; // here you'll get email id of user
userData.Remove("id");
userData.Remove("email");
AuthenticationResult result = new AuthenticationResult(true, ProviderName, id, username, userData);
return result;
}
}
////// Finally you need to register all stuffs in AuthConfig.cs and interact with Microsoft through our application.
OAuthWebSecurity.RegisterClient(new MicrosoftScopedClient(System.Configuration.ConfigurationManager.AppSettings["msClientId"].ToString(),
System.Configuration.ConfigurationManager.AppSettings["msClientSecret"].ToString(),
"wl.basic wl.emails"
)
, "Microsoft", null);
i'm making a request do a asp.net webapi Post Method, and i'm not beeing able to get a request variable.
Request
jQuery.ajax({ url: sURL, type: 'POST', data: {var1:"mytext"}, async: false, dataType: 'json', contentType: 'application/x-www-form-urlencoded; charset=UTF-8' })
.done(function (data) {
...
});
WEB API Fnx
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public void DoSomeStuff([FromBody]dynamic value)
{
//first way
var x = value.var1;
//Second way
var y = Request("var1");
}
i Cannot obtain the var1 content in both ways... (unless i create a class for that)
how should i do that?
First way:
public void Post([FromBody]dynamic value)
{
var x = value.var1.Value; // JToken
}
Note that value.Property actually returns a JToken instance so to get it's value you need to call value.Property.Value.
Second way:
public async Task Post()
{
dynamic obj = await Request.Content.ReadAsAsync<JObject>();
var y = obj.var1;
}
Both of the above work using Fiddler. If the first option isn't working for you, try setting the content type to application/json to ensure that the JsonMediaTypeFormatter is used to deserialize the content.
After banging my head around for a while on this and trying many different things I ended up putting some breakpoints on the API server and found the key value pairs stuffed down in the request. After I knew where they were, it was easy to access them. However, I have only found this method to work with WebClient.UploadString. However, it does work easily enough and allows you to load up as many parameters as you like and very easily access them server side. Note that I am targeting .net 4.5.
CLIENT SIDE
// Client request to POST the parameters and capture the response
public string webClientPostQuery(string user, string pass, string controller)
{
string response = "";
string parameters = "u=" + user + "&p=" + pass; // Add all parameters here.
// POST parameters could also easily be passed as a string through the method.
Uri uri = new Uri("http://localhost:50000/api/" + controller);
// This was written to work for many authorized controllers.
using (WebClient wc = new WebClient())
{
try
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
response = wc.UploadString(uri, login);
}
catch (WebException myexp)
{
// Do something with this exception.
// I wrote a specific error handler that runs on the response elsewhere so,
// I just swallow it, not best practice, but I didn't think of a better way
}
}
return response;
}
SERVER SIDE
// In the Controller method which handles the POST request, call this helper:
string someKeyValue = getFormKeyValue("someKey");
// This value can now be used anywhere in the Controller.
// Do note that it could be blank or whitespace.
// This method just gets the first value that matches the key.
// Most key's you are sending only have one value. This checks that assumption.
// More logic could be added to deal with multiple values easily enough.
public string getFormKeyValue(string key)
{
string[] values;
string value = "";
try
{
values = HttpContext.Current.Request.Form.GetValues(key);
if (values.Length >= 1)
value = values[0];
}
catch (Exception exp) { /* do something with this */ }
return value;
}
For more info on how to handle multi-value Request.Form Key/Value pairs, see:
http://msdn.microsoft.com/en-us/library/6c3yckfw(v=vs.110).aspx
I searched all morning to find an answer that depicted both client and server code, then finally figured it out.
Brief intro - The UI is an MVC 4.5 project that implements a standard view. The server side is an MVC 4.5 WebApi. The objective was to POST the model as JSON and subsequently update a database. It was my responsibility to code both the UI and backend. Below is the code. This worked for me.
Model
public class Team
{
public int Ident { get; set; }
public string Tricode { get; set; }
public string TeamName { get; set; }
public string DisplayName { get; set; }
public string Division { get; set; }
public string LogoPath { get; set; }
}
Client Side (UI Controller)
private string UpdateTeam(Team team)
{
dynamic json = JsonConvert.SerializeObject(team);
string uri = #"http://localhost/MyWebApi/api/PlayerChart/PostUpdateTeam";
try
{
WebRequest request = WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
WebResponse response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}
catch (Exception e)
{
msg = e.Message;
}
}
Server Side (WebApi Controller)
[Route("api/PlayerChart/PostUpdateTeam")]
[HttpPost]
public string PostUpdateTeam(HttpRequestMessage context)
{
var contentResult = context.Content.ReadAsStringAsync();
string result = contentResult.Result;
Team team = JsonConvert.DeserializeObject<Team>(result);
//(proceed and update database)
}
WebApiConfig (route)
config.Routes.MapHttpRoute(
name: "PostUpdateTeam",
routeTemplate: "api/PlayerChart/PostUpdateTeam/{context}",
defaults: new { context = RouteParameter.Optional }
);
Try this.
public string Post(FormDataCollection form) {
string par1 = form.Get("par1");
// ...
}
try using following way
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public static void DoSomeStuff(var value)
{
//first way
var x = value;
}
Currently, I use custom written authentication code for my site, which is built on .NET. I didn't take the standard Forms Auth route, as all the examples I could find were tightly integrated with WebForms, which I do not use. For all intents and purposes, I have all static HTML, and any logic is done through Javascript and web service calls. Things like logging in, logging off, and creating a new account are done without even leaving the page.
Here's how it works now: In the database, I have a User ID, a Security ID, and a Session ID. All three are UUIDs, and the first two never change. Each time the user logs on, I check the user table for a row that matches that username and hashed password, and I update the Session ID to a new UUID. I then create a cookie that's a serialized representation of all three UUIDs. In any secure web service calls, I deserialize that cookie that make sure there's a row in the users table with those 3 UUIDs. It's a fairly simple system and works well, however I don't really like the fact that a user can only be logged on with one client at a time. It's going to cause issues when I create mobile and tablet apps, and already creates issues if they have multiple computers or web browsers. For this reason, I'm thinking about throwing away this system and going with something new. Since I wrote it years ago, I figure there might be something much more recommended.
I've been reading up on the FormsAuthentication class in the .NET Framework, which handles auth cookies, and runs as an HttpModule to validate each request. I'm wondering if I can take advantage of this in my new design.
It looks like cookies are stateless, and sessions don't have to be tracked within the database. This is done through the fact that cookies are encrypted with a private key on the server, that can also be shared across a cluster of web servers. If I do something like:
FormsAuthentication.SetAuthCookie("Bob", true);
Then in later requests, I can be assured that Bob is indeed a valid user as a cookie would be very difficult if not impossible to forge.
Would I be wise to use the FormsAuthentication class to replace my current authentication model with? Rather than have a Session ID column in the database, I'd rely on encrypted cookies to represent valid sessions.
Are there third party/open source .NET authentication frameworks that might work better for my architecture?
Will this authentication mechanism cause any grief with code running on mobile and tablet clients, such as an iPhone app or Windows 8 Surface app? I would assume this would work, as long as these apps could handle cookies. Thanks!
Since I didn't get any responses, I decided to take a shot at this myself. First, I found an open source project that implements session cookies in an algorithm agnostic way. I used this as a starting point to implement a similar handler.
One issue I had with the built in ASP.NET implementation, which is a similar restriction in the AppHarbor implementation, is sessions are only keyed by a string username. I wanted to be able to store arbitrary data to identify a user, such as their UUID in the database as well as their logon name. As much of my existing code assumes this data is available in the cookie, it would take a lot of refactoring if this data were no longer available. Plus, I like the idea of being able to store basic user information without having to hit the database.
Another issue with the AppHarbor project, as pointed out in the this open issue, is the encryption algorithm isn't verified. This is not exactly true, as AppHarbor is algorithm agnostic, however it was requested that the sample project should show how to use PBKDF2. For that reason, I decided to use this algorithm (implemented in the .NET Framework through the Rfc2898DeriveBytes class) in my code.
Here's what I was able to come up with. It's meant as a starting point for someone looking to implement their own session management, so feel free to use it for whatever purpose you see fit.
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Web;
namespace AuthTest
{
[Serializable]
public class AuthIdentity : IIdentity
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public AuthIdentity() { }
public AuthIdentity(Guid id, string name)
{
Id = id;
Name = name;
}
public string AuthenticationType
{
get { return "CookieAuth"; }
}
public bool IsAuthenticated
{
get { return Id != Guid.Empty; }
}
}
[Serializable]
public class AuthToken : IPrincipal
{
public IIdentity Identity { get; set; }
public bool IsInRole(string role)
{
return false;
}
}
public class AuthModule : IHttpModule
{
static string COOKIE_NAME = "AuthCookie";
//Note: Change these two keys to something else (VALIDATION_KEY is 72 bytes, ENCRYPTION_KEY is 64 bytes)
static string VALIDATION_KEY = #"MkMvk1JL/ghytaERtl6A25iTf/ABC2MgPsFlEbASJ5SX4DiqnDN3CjV7HXQI0GBOGyA8nHjSVaAJXNEqrKmOMg==";
static string ENCRYPTION_KEY = #"QQJYW8ditkzaUFppCJj+DcCTc/H9TpnSRQrLGBQkhy/jnYjqF8iR6do9NvI8PL8MmniFvdc21sTuKkw94jxID4cDYoqr7JDj";
static byte[] key;
static byte[] iv;
static byte[] valKey;
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthenticateRequest += OnAuthenticateRequest;
context.EndRequest += OnEndRequest;
byte[] bytes = Convert.FromBase64String(ENCRYPTION_KEY); //72 bytes (8 for salt, 64 for key)
byte[] salt = bytes.Take(8).ToArray();
byte[] pw = bytes.Skip(8).ToArray();
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pw, salt, 1000);
key = k1.GetBytes(16);
iv = k1.GetBytes(8);
valKey = Convert.FromBase64String(VALIDATION_KEY); //64 byte validation key to prevent tampering
}
public static void SetCookie(AuthIdentity token, bool rememberMe = false)
{
//Base64 encode token
var formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, token);
byte[] buffer = stream.GetBuffer();
byte[] encryptedBytes = EncryptCookie(buffer);
string str = Convert.ToBase64String(encryptedBytes);
var cookie = new HttpCookie(COOKIE_NAME, str);
cookie.HttpOnly = true;
if (rememberMe)
{
cookie.Expires = DateTime.Today.AddDays(100);
}
HttpContext.Current.Response.Cookies.Add(cookie);
}
public static void Logout()
{
HttpContext.Current.Response.Cookies.Remove(COOKIE_NAME);
HttpContext.Current.Response.Cookies.Add(new HttpCookie(COOKIE_NAME, "")
{
Expires = DateTime.Today.AddDays(-1)
});
}
private static byte[] EncryptCookie(byte[] rawBytes)
{
TripleDES des = TripleDES.Create();
des.Key = key;
des.IV = iv;
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream, des.CreateEncryptor(), CryptoStreamMode.Write);
encrypt.Write(rawBytes, 0, rawBytes.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] encBytes = encryptionStream.ToArray();
//Add validation hash (compute hash on unencrypted data)
HMACSHA256 hmac = new HMACSHA256(valKey);
byte[] hash = hmac.ComputeHash(rawBytes);
//Combine encrypted bytes and validation hash
byte[] ret = encBytes.Concat<byte>(hash).ToArray();
return ret;
}
private static byte[] DecryptCookie(byte[] encBytes)
{
TripleDES des = TripleDES.Create();
des.Key = key;
des.IV = iv;
HMACSHA256 hmac = new HMACSHA256(valKey);
int valSize = hmac.HashSize / 8;
int msgLength = encBytes.Length - valSize;
byte[] message = new byte[msgLength];
byte[] valBytes = new byte[valSize];
Buffer.BlockCopy(encBytes, 0, message, 0, msgLength);
Buffer.BlockCopy(encBytes, msgLength, valBytes, 0, valSize);
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, des.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(message, 0, msgLength);
decrypt.Flush();
byte[] decMessage = decryptionStreamBacking.ToArray();
//Verify key matches
byte[] hash = hmac.ComputeHash(decMessage);
if (valBytes.SequenceEqual(hash))
{
return decMessage;
}
throw new SecurityException("Auth Cookie appears to have been tampered with!");
}
private void OnAuthenticateRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var cookie = context.Request.Cookies[COOKIE_NAME];
if (cookie != null && cookie.Value.Length > 0)
{
try
{
var formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
var bytes = Convert.FromBase64String(cookie.Value);
var decBytes = DecryptCookie(bytes);
stream.Write(decBytes, 0, decBytes.Length);
stream.Seek(0, SeekOrigin.Begin);
AuthIdentity auth = formatter.Deserialize(stream) as AuthIdentity;
AuthToken token = new AuthToken() { Identity = auth };
context.User = token;
//Renew the cookie for another 100 days (TODO: Should only renew if cookie was originally set to persist)
context.Response.Cookies[COOKIE_NAME].Value = cookie.Value;
context.Response.Cookies[COOKIE_NAME].Expires = DateTime.Today.AddDays(100);
}
catch { } //Ignore any errors with bad cookies
}
}
private void OnEndRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var response = context.Response;
if (response.Cookies.Keys.Cast<string>().Contains(COOKIE_NAME))
{
response.Cache.SetCacheability(HttpCacheability.NoCache, "Set-Cookie");
}
}
}
}
Also, be sure to include the following module in your web.config file:
<httpModules>
<add name="AuthModule" type="AuthTest.AuthModule" />
</httpModules>
In your code, you can lookup the currently logged on user with:
var id = HttpContext.Current.User.Identity as AuthIdentity;
And set the auth cookie like so:
AuthIdentity token = new AuthIdentity(Guid.NewGuid(), "Mike");
AuthModule.SetCookie(token, false);