D2L Valence: Auto-authentication in c# with app & user id/key - c#

the below is my code.
I'm building a c# window app to obtain some information from url without having to log in but auto-log in.
It's window app form that will output course offerings when user clicks the accept button. This code is based on valence-client-side sample code. I want this app to log in with the app id/key pair and user id/key pair and get course offerings and output them. But, when I run this program, it just stops var ctx = httpListener.GetContext(); at this line. I don't want it to open a browser but want to get auto-log in with app and user id/key pair in c#, and get json response from the url. so users do not have to log in.
namespace CourseOfferingWindow
{
class CourseOfferingResponse
{
public string Identifier { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public bool IsActive { get; set; }
public string Path { get; set; }
public object StartDate { get; set; }
public object EndDate { get; set; }
public string CourseTemplate { get; set; }
public string Semester { get; set; }
public string Department { get; set; }
}
public partial class CourseOfferingWindowForm : Form
{
public CourseOfferingWindowForm()
{
InitializeComponent();
}
private static ID2LUserContext InterceptUserTokens(HostSpec host, ID2LAppContext appContext)
{
// Start HTTP server and listen for the redirect after a successful auth
var httpListener = new HttpListener();
httpListener.Prefixes.Add("http://localhost:31337/result/");
httpListener.Start();
// This call blocks until we get a response
var ctx = httpListener.GetContext();
// The LMS returns the user tokens via query parameters to the value provided originally in x_target
// TODO: deal with "failed to login" case
var userContext = appContext.CreateUserContext(ctx.Request.Url, host);
// Send some JavaScript to close the browser popup
// This is not 100% effective: for example, Firefox will ignore this.
const string RESPONSE = "<!doctype html><meta charset=\"utf-8\"><script>window.close();</script><h1>You may now close your window</h1><p>You may or may not see this message, depending on your browser</p>";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(RESPONSE);
ctx.Response.ContentType = "text/html";
ctx.Response.ContentLength64 = buffer.Length;
ctx.Response.OutputStream.Write(buffer, 0, buffer.Length);
ctx.Response.OutputStream.Close();
httpListener.Stop();
return userContext;
}
private static void DoApiStuff(string host, ID2LUserContext userContext)
{
const string COURSEOFFERING_ROUTE = "/d2l/api/lp/1.0/courses/644849";
var client = new RestClient(host);
var valenceAuthenticator = new D2L.Extensibility.AuthSdk.Restsharp.ValenceAuthenticator(userContext);
var request = new RestRequest(COURSEOFFERING_ROUTE, Method.GET);
valenceAuthenticator.Authenticate(client, request);
var response = client.Execute<CourseOfferingResponse>(request);
Console.WriteLine("Hello, " + {course offerings information} );
}
private void ButtonAccept_Click(object sender, EventArgs e)
{
// This is the LMS we will interact with
var host = new HostSpec("https", "www.foltest.ca", 443);
// The appId/appKey come from our app.config - it is good to seperate access keys from the code that uses them.
// Ideally you wouldn't have production keys committed to source control.
string appId = ConfigurationManager.AppSettings["appId"];
string appKey = ConfigurationManager.AppSettings["appKey"];
// This is the port we will temporarily host a server on to intercept the user tokens after a successful login
int port = int.Parse(ConfigurationManager.AppSettings["serverPort"]);
// Create url for the user to login. If they have already done so they will not actually have to type their password (maybe).
var appContextFactory = new D2LAppContextFactory();
var appContext = appContextFactory.Create(appId, appKey);
var authUrl = appContext.CreateUrlForAuthentication(host, new Uri("http://localhost:" + port + "/result/"));
//OpenBrowser(authUrl);
// This call will block until we have a result
// TODO: you'll want better control flow and error handling here
var userContext = InterceptUserTokens(host, appContext);
// Now we can call Valence
DoApiStuff(host.Scheme + "://" + host.Host + ":" + host.Port, userContext);
// Pause the terminal
Console.ReadKey();
}
}
}
any kind of help will be appreciated. Thanks, Phillip

Instead of:
var authUrl = appContext.CreateUrlForAuthentication(host, new Uri("http://localhost:" + port + "/result/"));
//OpenBrowser(authUrl);
// call will block until we have a result
// TODO: you'll want better control flow and error handling here
var userContext = InterceptUserTokens(host, appContext);
// Now we can call Valence
DoApiStuff(host.Scheme + "://" + host.Host + ":" + host.Port, userContext);
do:
const string userId = "a_user_id"; // Use the correct user id
const string userKey = "a_user_key"; // Use the correct user key
var userContext = appContext.CreateUserContext(userId, userKey, host);
DoApiStuff(host.Scheme + "://" + host.Host + ":" + host.Port, userContext);
This assumes you have a Valence user id and key for the user account you want to use at your disposal. If you don't, you need to generate them out-of-band.

Related

API Connection - Migrate C# example to PHP (Wordpress)

I need to connect to an API. All examples that I could find use Tokens which I can send to each transaction I desire.
Accordingly to the supplier documentation, I couldn't find anything related to tokens.
The problem is when I connect, using curl or wp_remote_post() I don't have an 'connected' object to keep doing the transactions that I need.
Bellow is how it is done in C#. I need some directions in what objects I have to use and create the same functionality in php. Thanks
Connection Class:
public class RestService: IDisposable {
private readonly HttpClient _httpClient;
private readonly string _acumaticaBaseUrl;
public RestService(
string acumaticaBaseUrl, string userName, string password, string company, string branch, string locale) {
_acumaticaBaseUrl = acumaticaBaseUrl;
_httpClient = new HttpClient(
new HttpClientHandler {
UseCookies = true,
CookieContainer = new CookieContainer()
}) {
BaseAddress = new Uri(acumaticaBaseUrl + "/entity/Default/6.00.001/"),
DefaultRequestHeaders = {
Accept = {
MediaTypeWithQualityHeaderValue.Parse("text/json")
}
}
};
//Log in to MYOB Advanced
_httpClient.PostAsJsonAsync(
acumaticaBaseUrl + "/entity/auth/login", new {
name = userName,
password = password,
company = company,
branch = branch,
locale = locale
}).Result.EnsureSuccessStatusCode();
}
void IDisposable.Dispose() {
_httpClient.PostAsync(_acumaticaBaseUrl + "/entity/auth/logout", new ByteArrayContent(new byte[0])).Wait();
_httpClient.Dispose();
}
}
////////////////
//Data submission
public string Put(string entityName, string parameters, string entity) {
var res = _httpClient.PutAsync(_acumaticaBaseUrl + "/entity/Default/6.00.001/" + entityName + "?" + parameters, new StringContent(entity, Encoding.UTF8, "application/json")).Result.EnsureSuccessStatusCode();
return res.Content.ReadAsStringAsync().Result;
}
}

ASP.NET C# WebSocket

I have created an ASP.NET C# project which consists of a web form and a WebSocket handler. I would like to send 2 data (name & price data) from the web form in JSON string format to the WebSocket handler. Here is the code snippet in the web form:
ws.onopen = function()
{
var name = "Client Product";
var price = 10.8;
ws.send(JSON.stringify(name));
ws.send(JSON.stringify(price));
alert("Message is sent...");
};
In the WebSocket handler's OnMessage(string) method, I would like to retrieve the 2 data sent by the web form and deserialize the 2 data to c# format. Here is the code snippet in the WebSocket handler:
public override void OnMessage(string message)
{
string serverName="";
string serverPrice = "";
serverName = JsonConvert.DeserializeObject<string>(message);
serverPrice = JsonConvert.DeserializeObject<string>(message);
}
However, under the WebSocket handler's onMessage(string) method, both the variable serverName and serverPrice would be assigned as "Client Product". I want the variable serverPrice to be assigned as "10.8", instead of "Client Product".
Can somebody please tell me how I could achieve that? WILL really appreciate if you could help me :) Thank You :)
If you want to send multiple pieces of data in a single JSON message, you'll need to combine them into an object. Try it like this:
On the client:
ws.onopen = function()
{
var obj = {
name: "Client Product",
price: "10.8"
};
ws.send(JSON.stringify(obj));
alert("Message is sent...");
};
On the server:
public override void OnMessage(string message)
{
MyData obj = JsonConvert.DeserializeObject<MyData>(message);
string serverName = obj.Name;
string serverPrice = obj.Price;
...
}
public class MyData
{
// Important: these JsonProperty attributes MUST match
// the names of the properties in the client object
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("price")]
public string Price { get; set; }
}

Adobe Sign (echo sign) API sending document using C#

Okay I have limited understanding of working with API's
Im trying to get to grips with Adobe Sign API and hit a dead end, on there test page i have enterd this and it works
But i have no idea on how then do that in C#
I have tried the following, but know its missing the OAuth stuff and I'm just not sure what to try next.
by the way foo.GetAgreementCreationInfo() just gets the string that is in the screen shot, I just moved it out cus it was big and ugly
var foo = new Models();
var client = new RestClient("https://api.na1.echosign.com/api/rest/v5");
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("agreements/{AgreementCreationInfo}", Method.POST);
request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method
request.AddUrlSegment("AgreementCreationInfo", foo.GetAgreementCreationInfo()); // replaces matching token in request.Resource
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
You are misinterpreting the API documentation. The Access-Token parameter needed in your API is clearly an HTTP header, while the AgreementCreationInfo is simply the request body in JSON format. There is no URI segment, so rewrite your code as follows:
var foo = new Models();
//populate foo
var client = new RestClient("https://api.na1.echosign.com/api/rest/v5");
var request = new RestRequest("agreements", Method.POST);
request.AddHeader("Access-Token", "access_token_here!");
// request.AddHeader("x-api-user", "userid:jondoe"); //if you want to add the second header
request.AddParameter("application/json", foo.GetAgreementCreationInfo(), ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
var content = response.Content;
Please also be aware that in RESTSharp you do not need to manually serialize your body into JSON at all. If you create a strongly typed object (or just an anonymous object could be enough) that has the same structure of your final JSON, RESTSharp will serialize it for you.
For a better approach I strongly suggest you to replace this line:
request.AddParameter("application/json", foo.GetAgreementCreationInfo(), ParameterType.RequestBody);
With those:
request.RequestFormat = DataFormat.Json;
request.AddBody(foo);
Assuming your foo object is of type Models and has the following structure along with its properties:
public class Models
{
public DocumentCreationInfo documentCreationInfo { get; set; }
}
public class DocumentCreationInfo
{
public List<FileInfo> fileInfos { get; set; }
public string name { get; set; }
public List<RecipientSetInfo> recipientSetInfos { get; set; }
public string signatureType { get; set; }
public string signatureFlow { get; set; }
}
public class FileInfo
{
public string transientDocumentId { get; set; }
}
public class RecipientSetInfo
{
public List<RecipientSetMemberInfo> recipientSetMemberInfos { get; set; }
public string recipientSetRole { get; set; }
}
public class RecipientSetMemberInfo
{
public string email { get; set; }
public string fax { get; set; }
}
Link to AdobeSign Repository:
ADOBE SIGN SDK C# SHARP API Ver. 6
Adobe Sign API integrators - this is kind of hidden away in AdobeSigns GIT repositories. The link to all the generated SWAGGER classes (models/methods) for C# and REST client integrated C# project in a GIT project you can compile and use right inside your project as a project reference or compiled DLL. This project has been updated to use version 6 of the API. This was a huge time saver for me. I have provided a quick example below on how to use it. I hope this helps others save time as well.
Note you might have to switch out BasePath in the configuration.cs so you can retrieve the initial Adobe URI "BaseURI" call if you get 404 error.
Change BasePath = "http://localhost/api/rest/v6";
To:
BasePath = "https://api.echosign.com/api/rest/v6";
//include namespaces:
using IO.Swagger.Api;
using IO.Swagger.model.agreements;
using IO.Swagger.model.baseUris;
using IO.Swagger.model.transientDocuments;
using System.IO;
Then this quick minimal demonstrates BaseUri, Upload PDF a.k.a. Transient Document, then Create Agreement (Example 1 Basic Signer Minimal Options)
string transientDocumentId = "";
string adobesignDocKey = "";
string baseURI = "";
var apiInstanceBase = new BaseUrisApi();
var authorization = "Bearer " + apiKey; //Example as Integration Key, see adobesign docs For OAuth.
try
{
//___________________GET BASEURI ADOBE SIGN_________________________
BaseUriInfo resultBase = apiInstanceBase.GetBaseUris(authorization);
baseURI = resultBase.ApiAccessPoint; //return base uri
//___________________UPLOAD YOUR PDF THEN REF ADOBE SIGN_________________________
var apiInstanceFileUpload = new TransientDocumentsApi(baseURI + "api/rest/v6/");
TransientDocumentResponse resultTransientID = apiInstanceFileUpload.CreateTransientDocument(authorization, File.OpenRead([ENTER YOUR LOCAL FILE PATH]), null, null, _filename, null);
if (!String.IsNullOrEmpty(resultTransientID.TransientDocumentId))
{
transientDocumentId = resultTransientID.TransientDocumentId; //returns the transient doc id to use below as reference
}
var apiInstance = new AgreementsApi(baseURI + "api/rest/v6/");
//___________________CREATE ADOBE SIGN_________________________
var agreementId = ""; // string | The agreement identifier, as returned by the agreement creation API or retrieved from the API to fetch agreements.
var agreementInfo = new AgreementCreationInfo();
//transientDocument, libraryDocument or a URL (note the full namespace/conflicts with System.IO
List<IO.Swagger.model.agreements.FileInfo> useFile = new List<IO.Swagger.model.agreements.FileInfo>();
useFile.Add(new IO.Swagger.model.agreements.FileInfo { TransientDocumentId = transientDocumentId });
agreementInfo.FileInfos = useFile;
//Add Email To Send To:
List<ParticipantSetMemberInfo> partSigners = new List<ParticipantSetMemberInfo>();
partSigners.Add( new ParticipantSetMemberInfo { Email = "[ENTER VALID EMAIL SIGNER]", SecurityOption=null });
//Add Signer To Participant
List<ParticipantSetInfo> partSetInfo = new List<ParticipantSetInfo>();
partSetInfo.Add(new ParticipantSetInfo { Name = "signer1", MemberInfos = partSigners, Role = ParticipantSetInfo.RoleEnum.SIGNER, Order=1, Label="" });
agreementInfo.ParticipantSetsInfo = partSetInfo;
agreementInfo.SignatureType = AgreementCreationInfo.SignatureTypeEnum.ESIGN;
agreementInfo.Name = "Example Esign For API";
agreementInfo.Message = "Some sample Message To Use Signing";
agreementInfo.State = AgreementCreationInfo.StateEnum.INPROCESS;
AgreementCreationResponse result = apiInstance.CreateAgreement(authorization, agreementInfo, null, null);
adobesignDocKey = result.Id; //returns the document Id to reference later to get status/info on GET
}
catch (Exception ex)
{
//Capture and write errors to debug or display to user
System.Diagnostics.Debug.Write(ex.Message.ToString());
}

C# post json example to .vb

Im trying to convert a C# example thats posting to a API into .vb.
My programming skills are limited so I cant seem to get it to work.
One problem is that I cant use httpclient cause the project is in Framework 3.5 and thats something I cant change. Anyone?
Here is the c# code:
public class TriggerData
{
//if true, the contact will be updated with sent property data (affects performance).
public bool saveProps { get; set; }
public string originalId { get; set; }
public Dictionary<string, string> properties { get; set; }
public TriggerData()
{
properties = new Dictionary<string, string>();
}
}
public class CarmaTriggerClient
{
static void Main(string[] args)
{
//use your settings here
var host = "https://www.adress.com";
var customerId = 0;
var triggerId = 0;
var user = "";
var pass = "";
var data = new TriggerData();
//unique identifier in the list
data.originalId = "th#post.se";
///property keys are emailAddress, mobileNumber, firstName, lastName, city, zip, country, middleName, title, dateOfBirth, sex, or the id of one of your custom properties
data.properties["emailAddress"] = "th#post.se";
data.properties["4321"] = "some data";
//REST resource for trigger
var path = string.Format("/rest/{0}/triggers/{1}/messages", customerId, triggerId);
TriggerAsync(host, path, user, pass, data).Wait();
}
static async Task TriggerAsync(string host, string path, string user, string pass, TriggerData data)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(host);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var credentials = string.Format("{0}:{1}", user, pass);
//http://www.ietf.org/rfc/rfc2617.txt
var authorization = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(credentials));
client.DefaultRequestHeaders.Add("Authorization", "Basic " + authorization);
// HTTP POST
var response = await client.PostAsJsonAsync(path, data);
if (!response.IsSuccessStatusCode)
{
System.Diagnostics.Debug.WriteLine(response.Content);
}
}
}
}
}
Search for csharp vbnet online converter and you will find, for example, http://www.carlosag.net/tools/codetranslator/
I checked your code. It does translate.
Framework versions are the same regarding vbnet and csharp; which is another question.
HTH

Cannot run a restfull server in a ASP.Net without MVC

I'm trying to run a simple restfull server in a simple asp.net application without the mvc(following this tutorial : http://www.codeproject.com/Articles/769671/Web-API-without-MVC
(which will trun into a online portal).
here is my class :
public class Foods
{
public string FoodName { get; set; }
public string Price { get; set; }
public string Type { get; set; }
public string Content { get; set; }
public Foods()
{
}
}
and here is my controller:
public class FoodController : ApiController
{
public List<Foods> _productList;
public List<Foods> GetProductList()
{
_productList = new List<Foods>{
new Foods{FoodName= "pizza",Content= "bread cheese",Type="Main",Price="100"},
new Foods{FoodName= "rice",Content= "rice and ...",Type="Main",Price="100"}
};
return _productList;
}
}
and here is my asp.net page code(it is simple nothing to show):
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var config = new HttpSelfHostConfiguration("http://localhost:8080/");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = System.Web.Http.RouteParameter.Optional });
using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
}
}
}
when i run it there is no error and the blank page is shown
and here is the client which is a simple c# form with a list box and a button:
private void button1_Click(object sender, EventArgs e)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:8080/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
try
{
HttpResponseMessage response = client.GetAsync("api/foods").Result;
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
var foods = response.Content.ReadAsAsync<IEnumerable<Foods>>().Result;
foreach (Foods food in foods)
{
string foodinfo = food.FoodName + " " + food.Content + " " + food.Type + " " + food.Price;
listBox1.Items.Add(foodinfo);
}
}
}
catch (Exception ex)
{
textBox1.Text = ex.ToString();
}
}
but when i run the client and click the button i get this error:
System.AggregateException: One or more errors occurred.
System.Net.Sockets.SocketException: No connection could be made
because the target machine actively refused it 127.0.0.1:8080
There could be one or more reason for it.
1) Make sure that the port 8080 is not consumed by other application, Try running on different port.
try client.BaseAddress = new Uri("http://localhost:9090/");
2) By default, listening at a particular HTTP address requires administrator privileges. When you run the application, therefore, you might get an error: "HTTP could not register URL http://+:8080/".To avoid this error, run Visual Studio with elevated administrator permissions.
3) Make sure that both projects are running parallelly. If not do it.
Go to Solution properties -> Common properties -> Startup Project and select Multiple startup projects

Categories