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.
Related
Is there a way of logging the request and response from the client layer(not from controller as we can use middleware to log the same there).
I am looking to eliminate developer code for audit log here (//log request ,//log response and and creating a provider context ) instead move them to a common handler , may be inherit from delegating handler delegating handler and have the Audit log code there.
Any ideas ?
Currently we have audit logging in the client where another service is called but the developer has to do the following :
Client layer code:
{
IRestResponse response = null;
ConnectorHTMLResponse CCMSResponse = null;
request.Validate(request.TemplateName);
var providerContext = _messageTracker.CreateProviderContext(correlationId, "MailTrigger", "GetHTML", OperationProtocols.HTTPS);
//log request
await providerContext.StartAsync(request, param => request.TemplateName);
var bodyJson = ToBodyJson(request, TemplateType.HTML);
try
{
response = await ExecuteAsync(bodyJson, correlationId);
}
catch (Exception ex)
{
await providerContext.RaiseExceptionAsync(ex);
throw;
}
Response = ConstructHTMLDocumentDetails(ValidateResponse(response));
//log response
await providerContext.CompletedAsync(Response);
return Response;
}
//and in the message tracker(Common code )
public static ProviderContext CreateProviderContext(this IMessageTracker messageTracker, string correlationId, string systemId, string operationName, OperationProtocols protocol)
{
var context = new ProviderContext(
messageTracker,
correlationId,
systemId,
operationName,
Assembly.GetCallingAssembly().GetName().Name,
protocol
);
return context;
}
public async Task StartAsync<T>(T payload, Func<T, string> primaryIdentifierFunc = null, Func<T, string> secondaryIdentifierFunc = null)
{
await StartAsync(payload, primaryIdentifierFunc?.Invoke(payload), secondaryIdentifierFunc?.Invoke(payload));
}
public async Task CompletedAsync<T>(T payload, Func<T, string> primaryIdentifierFunc = null, Func<T, string> secondaryIdentifierFunc = null)
{
_source.Payload = payload.AsPayload();
_source.PrimaryIdentifier = primaryIdentifierFunc?.Invoke(payload) ?? _source.PrimaryIdentifier;
_source.SecondaryIdentifier = secondaryIdentifierFunc?.Invoke(payload) ?? _source.SecondaryIdentifier;
await _tracker.TrackProviderResponseAsync(
//track in cloud
);
}``
I can't see the result that I send from a Visual Basic 2019 Xamarin Forms app to a PHP REST. Basically this is what I do in the Mainpage.xaml.cs:
protected override async void OnAppearing()
{
HttpClient client = new HttpClient();
Uri uri = new Uri("https://www.miweb.com/prueba.php");
Msj mensaje = new Msj { Mensaje = "PRUEBAAAAAA" };
string json = JsonConvert.SerializeObject(mensaje);
var content = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
//HttpResponseMessage response = client.PostAsync(uri, content).Result;
using (var response = await client.PostAsync(uri, content))
{
}
base.OnAppearing();
}
The class Msj:
internal class Msj
{
public string Mensaje { get; internal set; }
}
And this is the PHP code:
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
$input = $_POST;
header("HTTP/1.1 200 OK");
$file = fopen("app.txt", "w");
fwrite($file, json_encode($input['Mensaje']) . PHP_EOL);
fclose($file);
exit();
}
The app.txt file is created, but its content is "null" (without quotes.)
To view the sent data you can use:
print_r($_POST);
From this you should be able to work out what is/isn't being sent and alter your code from there.
Finally I solved so, without JSON. Thanks to all:
protected override async void OnAppearing()
{
HttpClient client = new HttpClient();
Uri uri = new Uri("https://www.miweb.com/prueba.php");
var datos = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("mensaje", "SOLVED!")
};
var content = new FormUrlEncodedContent(datos);
using (var response = await client.PostAsync(uri, content))
{
}
base.OnAppearing();
}
I had the similar problem, I was trying to post to a website URL without index.php at the end, as I thought it wasn't needed. The script was posted to but POST variables were none.
When I appended "/index.php" to the URL, POST variables were there.
It is strange behavior.
A simple Spring Boot REST Controller
#PostMapping(path = "check-and-submit", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MyOutput> checkAndSave(#RequestBody #Valid MyInput input, Errors errors){
ResponseEntity<MyOutput> result = null;
if (errors.hasErrors()) {
result = new ResponseEntity<>(MyOutput.buildErrorResponse(errors), HttpStatus.INTERNAL_SERVER_ERROR);
} else {
myDao.save(input.buildEntity());
result = new ResponseEntity<>(MyOutput.buildSuccessResponse(), HttpStatus.OK);
}
return result;
}
And the test class for it
public static void main(String[] args) {
MyInput dto = new MyInput();
// set properties
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", "application/json");
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<MyInput> request = new HttpEntity<MyInput>(dto, headers);
try {
ResponseEntity<MyOutput> result = restTemplate.postForEntity(URL, request, MyOutput.class);
System.out.println(result);
} catch(Exception e) {
e.printStackTrace();
}
}
For success scenario this works fine. But, for exception scenrio, i.e. HTTP 500 this fails
org.springframework.web.client.HttpServerErrorException: 500 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:97)
As suggested in one of the posts, I created a error-handler that can successfully read the response
public class TestHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
Scanner scanner = new Scanner(response.getBody());
String data = "";
while (scanner.hasNext())
data += scanner.next();
System.out.println(data);
scanner.close();
}
}
But how can I let RestTemplate read and deserialize the response JSON even in case of HTTP 500.
Before any other human-question-flagging-bot marks this as duplicate, here's a humble explanation on how this is different from the others.
All other questions address how to handle HTTP 500, at max read the response-body. This questions is directed at if it is possible to deserialize the response as JSON as well. Such functionality is well established in frameworks such as JBoss RESTEasy. Checking how same can be achieved in Spring.
This should work.
try {
ResponseEntity<MyOutput> result = restTemplate.postForEntity(URL, request, MyOutput.class);
} catch(HttpServerErrorException errorException) {
String responseBody = errorException.getResponseBodyAsString();
// You can use this string to create MyOutput pojo using ObjectMapper.
}
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;
}
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.