Fire TriggeredSends from ExactTarget's API using HttpClient REST - c#

I've read along the way that Salesforce (I'm extremely new to this 3rd party platform) has a FUEL SDK which one can use instead of the version (using HttpClient -- REST instead of SOAP).
Please correct me if using FUEL SDK is the only way to go about requesting Salesforce's endpoints. Currently I am attempting to hit ExactTargets's API endpoints using HttpClient. These are the tutorials I've been basing my code off of:
https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/messageDefinitionSends.htm
https://developer.salesforce.com/docs/atlas.en-us.mc-getting-started.meta/mc-getting-started/get-access-token.htm
Wanted Result:
To be able to request a Triggered Send email based off a template inside of ExactTarget.
Problem:
The Salesforce endpoint continuously returns a 404. I am able to receive the authorization token successfully. The GetAccessToken method is omitted for brevity
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
I do not understand why the 2nd POST request to //www.exacttargetapis.com/..... returns a 404 but the authorization works. This leads me to believe that I do not have to use the FUEL SDK to accomplish triggering a welcome email.
Code:
private const string requestTokenUrl = "https://auth.exacttargetapis.com/v1/requestToken";
private const string messagingSendUrl = "https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends";
private string exactTargetClientId = ConfigurationManager.AppSettings["ExactTargetClientId"];
private string exactTargetClientSecret = ConfigurationManager.AppSettings["ExactTargetClientSecret"];
private string TriggerEmail(User model, string dbName)
{
var etExternalKeyAppSetting = ConfigurationManager.AppSettings.AllKeys.FirstOrDefault(x => x.Equals(dbName));
if (etExternalKeyAppSetting != null)
{
string etExternalKey = ConfigurationManager.AppSettings[etExternalKeyAppSetting];
HttpClient client = new HttpClient
{
BaseAddress = new Uri(string.Format(#"{0}/key:{1}/send", messagingSendUrl, etExternalKey)),
DefaultRequestHeaders =
{
Authorization = new AuthenticationHeaderValue("Bearer", this.GetAccessToken())
}
};
try
{
var postData = this.CreateExactTargetPostData(model.Email, etExternalKey);
var response = client.PostAsync(client.BaseAddress
, new StringContent(JsonConvert.SerializeObject(postData).ToString()
, Encoding.UTF8
, "application/json")).Result;
// get triggered email response
if (response.IsSuccessStatusCode)
{
dynamic result = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{
string message = ex.Message;
}
}
return "testing";
}
private object CreateExactTargetPostData(string email, string extKey)
{
var fromData = new
{
Address = ConfigurationManager.AppSettings["AwsSenderEmail"],
Name = "Test"
};
var subscriberAttributes = new { };
var contactAttributes = new
{
SubscriberAttributes = subscriberAttributes
};
var toData = new
{
Address = email,
//SubscriberKey = extKey,
//ContactAttributes = contactAttributes
};
var postData = new
{
From = fromData,
To = toData
};
return postData;
}
I have also tried using Advanced REST Client using the following:
URL:
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
POST
Raw Headers:
Content-Type: application/json
Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Raw Payload:
{
"From": {
"Address": "code#exacttarget.com",
"Name": "Code#"
},
"To": {
"Address": "example#example.com",
"SubscriberKey": "example#example.com",
"ContactAttributes": {
"SubscriberAttributes": {
"Region": "West",
"City": "Indianapolis",
"State": "IN"
}
}
},
"OPTIONS": {
"RequestType": "ASYNC"
}
}

Issue was my App in the AppCenter was pointing to the incorrect login for MarketingCloud =(

Related

How to Post data with Subdetails in Web API using c# WPF?

When I Post this Data Throw Postman To Web API((http://192.168.18.15/api/PostData)) it works for me and gives me 200 OK Success CODE
Method: POST,
Headers: Content-Type: application/json,
cache-control: no-cache
[
{
"Code": "900350491",
"FullName":"John Setalh",
"OrgCode": "13",
"OrgDescription": "Microsoft Services",
"RegCode": "11",
"DISTRICT_CODE": "900",
"ACCOUNT_NO": "00012043",
"BANK_ACCOUNT_NO": "00003043",
"DESCRIPTIONS": "just test the System",
"AMOUNT": "300",
"SUB_DETAILS":
[
{
"Unit": "73000",
"ReCode": "13300",
"ReDes":"Some Description",
"ReAmount": "0"
}
]
}
]
Now I want to Implement C# Code to Post this JSON data and I tried this Code:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer",mytoken);
client.BaseAddress = new Uri("http://192.168.18.15/");
MyModel r = new MyModel();
r.Code = "12354";
r.FullName = "FullName Here";
r.OrgCode = "73";
r.OrgDescription= "SomeDescription";
r.RegCode = "50";
r.DISTRICT_CODE = "230";
r.ACCOUNT_NO = "00012043";
r.BANK_ACCOUNT_NO = "00203043";
r.DESCRIPTIONS = "just test the System";
r.AMOUNT = "300";
r.SUB_DETAILS.Unit="73000";
r.SUB_DETAILS.ReCode="13300";
r.SUB_DETAILS.ReDes="Some Description";
r.SUB_DETAILS.ReAmount="300";
var sendData = client.PostAsJsonAsync("api/PostData", new List<MyModel> {r}).Result;
var result = sendData.Content.ReadAsStringAsync();
string TariffNos = result.Result;
}
it gives me an error Message: Wrong Attempt Status Code:400 Error: UnAuthorized
can anyone help me where is the Problems my Token is Correct why it give that Error
thanks
your model should be a collection, since you are using collection for postman. Try this model
var sendData = client.PostAsJsonAsync("api/PostData", new List<MyModel> {r}).Result;
and try to add a content type
var contentType = new MediaTypeWithQualityHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(contentType);

Read metadata in grpc on the server side c#

I am sending token in metadata from the client side
Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
ItemQuery item = new ItemQuery() { Id = "abc" };
var client = new MyService.MyServiceClient(channel);
Metadata data = new Metadata
{
{ "token", "Bearer xhrttt" }
};
var reply = client.GetItem(item, data);
But not able to find a way to fetch it in server side, Any help is appreciated
below is an example of how my server-side code looks(i tried certain other ways also)
public override Task<ItemResponse> GetItem(ItemQuery request , ServerCallContext context)
{
try
{
var a = context.RequestHeaders["token"]; // not working
ItemResponse itmRes = new ItemResponse();
if (request.Id == "foo")
{
itmRes.Items.Add(new Item() { Id = "foo", Name = "foobar" });
}
return Task.FromResult(itmRes);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
return null;
}
Below is the code to fetch metadata in c#
Metadata.Entry metadataEntry = context.RequestHeaders.FirstOrDefault(m =>
String.Equals(m.Key, "token", StringComparison.Ordinal));
if (metadataEntry.Equals(default(Metadata.Entry)) || metadataEntry.Value == null)
{
return null;
}
Console.WriteLine("Token value is {0}", metadataEntry.Value);
for more details refer https://csharp.hotexamples.com/examples/Grpc.Core/ServerCallContext/-/php-servercallcontext-class-examples.html
Based on this tutorial, this and this, getting and setting metadata can be summarized:
GreeterService.cs (GrpcGreeter.csproj)
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
context.WriteResponseHeadersAsync(
new Metadata() { { "server_header", "nice to see you too" } });
context.ResponseTrailers.Add(
new Metadata.Entry("server_trailer", "see you later") { });
string? client_header = context.RequestHeaders.GetValue("client_header");
return Task.FromResult(new HelloReply
{
Message = $"i got your header, {request.Name}. it reads: {client_header}"
});
}
Program.cs (GrpcGreeterClient.csproj)
// The port number must match the port of the gRPC server.
using var channel = GrpcChannel.ForAddress("https://localhost:7143");
Greeter.GreeterClient client = new Greeter.GreeterClient(channel);
var call = client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" },
new Metadata() { { "client_header", "hey there" } });
Metadata headers = await call.ResponseHeadersAsync;
Console.WriteLine($"Server Header: {headers.GetValue("server_header")}");
HelloReply rsp = await call.ResponseAsync;
Console.WriteLine($"Server Response: {rsp.Message}");
Metadata trailers = call.GetTrailers();
string? myTrailer = trailers.GetValue("server_trailer");
Console.WriteLine($"Server Trailers: {myTrailer}");
Output:
Server Header: nice to see you too
Server Response: i got your header, GreeterClient. it reads: hey there
Server Trailers: see you later

YouTrack REST API - Create new priority

I I’m looking for a way to create a new priority value with the REST API.
In the documentation I found the following endpoint:
/rest/admin/customfield/bundle/{bundleName}/{fieldValue}?{description}&{colorIndex}
Calling this endpoint returns a 415 status code with the content:
{"value":"Unsupported Media Type"}
Here is my code:
var connection = YouTrackConnectionFactory.GetConnection();
var client = await connection.GetAuthenticatedHttpClient();
var priorityValue = "SomeNewPrio";
var enumerationName = "Priorities";
var queryString = new Dictionary<String, String>
{
{ "bundleName", enumerationName },
{ "fieldValue", priorityValue },
{ "description", WebUtility.UrlEncode( "Automatically created priority" ) },
{ "colorIndex", "9" }
};
var response = await client.PutAsync( $"/rest/admin/customfield/bundle/{enumerationName}/{priorityValue}", new FormUrlEncodedContent( queryString ) );
response.EnsureSuccessStatusCode();
Is there something wrong with my data or is there another endpoint I should be using?

Getting "error": "unsupported_grant_type" when trying to get a JWT by calling an OWIN OAuth secured Web Api via Postman

I have followed this article to implement an OAuth Authorization server. However when I use post man to get a token, I get an error in the response:
"error": "unsupported_grant_type"
I read somewhere that the data in Postman needs to be posted using Content-type:application/x-www-form-urlencoded. I have prepped the required settings in Postman:
and yet my headers are like this:
Here is my code
public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" });
context.OwinContext.Response.StatusCode = 200;
context.RequestCompleted();
return Task.FromResult<object>(null);
}
return base.MatchEndpoint(context);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
string allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Content-Type" });
Models.TheUser user = new Models.TheUser();
user.UserName = context.UserName;
user.FirstName = "Sample first name";
user.LastName = "Dummy Last name";
ClaimsIdentity identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
foreach (string claim in user.Claims)
{
identity.AddClaim(new Claim("Claim", claim));
}
var ticket = new AuthenticationTicket(identity, null);
context.Validated(ticket);
}
}
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
In the CustomJWTFormat class above only the breakpoint in the constructor gets hit. In the CustomOauth class, the breakpoint in the GrantResourceOwnerCredentials method never gets hit. The others do.
The Startup class:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
app.UseWebApi(config);
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
var OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["Issuer"])
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
string issuer = ConfigurationManager.AppSettings["Issuer"];
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
}
Do I need to set up Content-type:application/x-www-form-urlencoded somewhere else in the web api code? What could be wrong? Please help.
The response is a bit late - but in case anyone has the issue in the future...
From the screenshot above - it seems that you are adding the url data (username, password, grant_type) to the header and not to the body element.
Clicking on the body tab, and then select "x-www-form-urlencoded" radio button, there should be a key-value list below that where you can enter the request data
With Postman, select Body tab and choose the raw option and type the following:
grant_type=password&username=yourusername&password=yourpassword
Note the URL: localhost:55828/token (not localhost:55828/API/token)
Note the request data. Its not in json format, its just plain data without double quotes.
userName=xxx#gmail.com&password=Test123$&grant_type=password
Note the content type. Content-Type: 'application/x-www-form-urlencoded' (not Content-Type: 'application/json')
When you use JavaScript to make post request, you may use following:
$http.post("localhost:55828/token",
"userName=" + encodeURIComponent(email) +
"&password=" + encodeURIComponent(password) +
"&grant_type=password",
{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }}
).success(function (data) {//...
See screenshots below from Postman:
If you are using AngularJS you need to pass the body params as string:
factory.getToken = function(person_username) {
console.log('Getting DI Token');
var url = diUrl + "/token";
return $http({
method: 'POST',
url: url,
data: 'grant_type=password&username=myuser#user.com&password=mypass',
responseType:'json',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
};
try to add this in your payload
grant_type=password&username=pippo&password=pluto
I was getting this error too and the reason ended up being wrong call url. I am leaving this answer here, if someone else happens to mix the urls and getting this error. Took me hours to realize I had wrong URL.
Error I got (HTTP code 400):
{
"error": "unsupported_grant_type",
"error_description": "grant type not supported"
}
I was calling:
https://MY_INSTANCE.lightning.force.com
While the correct URL would have been:
https://MY_INSTANCE.cs110.my.salesforce.com
Old Question, but for angular 6, this needs to be done when you are using HttpClient
I am exposing token data publicly here but it would be good if accessed via read-only properties.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { delay, tap } from 'rxjs/operators';
import { Router } from '#angular/router';
#Injectable()
export class AuthService {
isLoggedIn: boolean = false;
url = "token";
tokenData = {};
username = "";
AccessToken = "";
constructor(private http: HttpClient, private router: Router) { }
login(username: string, password: string): Observable<object> {
let model = "username=" + username + "&password=" + password + "&grant_type=" + "password";
return this.http.post(this.url, model).pipe(
tap(
data => {
console.log('Log In succesful')
//console.log(response);
this.isLoggedIn = true;
this.tokenData = data;
this.username = data["username"];
this.AccessToken = data["access_token"];
console.log(this.tokenData);
return true;
},
error => {
console.log(error);
return false;
}
)
);
}
}
Another common cause of this 'unsupported_grant_type' error is calling the API as GET instead of POST.
In Angular 13, this is what I did;
let headers = new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
return this.http.post(this.url + 'token', 'grant_type=password&username='+form.username+'&password='+form.password, { headers: headers})
Use grant_type={ Your password}

Simple HTTP POST with an anonymous type as body

I can't really find a working example, maybe it is because its simply not possible?
I'd like to take a C# anonymous type object like the following:
var postBody = new
{
friend = new
{
name = "dave",
last ="franz"
},
id = "12345",
login = "mylogin"
};
and post it to my web service in a simple http POST with the following post body:
{
"friend" :
{
"name" : "dave",
"last" : "franz"
},
"id" : "12345",
"login" : "mylogin"
};
Pretty easy using Json.net. You can get it using the nuget package manager in VS.
var postBody = new
{
friend = new
{
name = "dave",
last ="franz"
},
id = "12345",
login = "mylogin"
};
var postString = Newtonsoft.Json.JsonConvert.SerializeObject(postBody);
using(var wc = new WebClient())
{
wc.Headers.Add("Content-Type", "application/json");
var responseString = wc.UploadString(serviceAddress, "POST", postString);
}
If you have HttpClient client:
var request = new HttpRequestMessage(HttpMethod.Post, "<URL>") {
Content = JsonContent.Create(new {
Prop = "Value"
})
};
var response = await client.SendAsync(request);

Categories