I have a C# unity function and I'm trying to request some json from a webserver but for some reason its not exiting the function where I want it to:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Proyecto26;
using UnityEditor;
using UnityEngine.Networking;
using System.Text;
using TMPro;
using SimpleJSON;
public class APIRequest
{
// string basicRequestPage = "****";
string basicAPI_Key = "****";
// Start is called before the first frame update
string outputs;
public string basicRequest(int requestTyp)
{
auth test1 = new auth();
test1.key = basicAPI_Key;
switch (requestTyp)
{
case 0:
test1.request = "deckList";
break;
case 1:
test1.request = "card";
break;
}
string output = JsonConvert.SerializeObject(test1);
byte[] outputToServer = Encoding.ASCII.GetBytes(output); ;
//Debug.Log(output);
RestClient.Request(new RequestHelper
{
Uri = basicRequestPage,
Method = "POST",
Timeout = 10,
//EnableDebug = true,
ParseResponseBody = false, //Don't encode and parse downloaded data as JSONe
BodyRaw = outputToServer
}).Then(response =>
{
// EditorUtility.DisplayDialog("Status", response.Text, "Ok");
var rest = response.Text;
//Debug.Log(rest);
outputs = rest.ToString();
//EditorUtility.DisplayDialog("Status", outputs, "Ok");
return outputs;
}).Catch(err =>
{
var error = err as RequestException;
EditorUtility.DisplayDialog("Error Response", error.Response + "", "Ok");
}
);
}
}
Link to code because it wouldn't work with the built in code text
It works perfectly fine as a method but keeps complaining that I don't have a valid return from the function. When I try to return the value I get from API, namely the outputs variable, it says it null. I have tried putting it in the function, in a public variable. but to now avail.
Any ideas?
When you're working with promises you need to return a promise from that method too (Promise chaining):
public IPromise<string> basicRequest(int requestTyp)
{
return RestClient.Request(new RequestHelper
{
Uri = basicRequestPage,
Method = "POST",
Timeout = 10,
//EnableDebug = true,
ParseResponseBody = false, //Don't encode and parse downloaded data as JSONe
BodyRaw = outputToServer
}).Then(response => response.Text.ToString());
}
For more details, check the repository of the Promises library used by the RestClient for Unity here.
You have defined an output of type string however you do not return a string at all exits. After the catch you have to return a string either at the end of the method or in the catch. The last line I have added return ""; should solve the problem.
public string basicRequest(int requestTyp)
{
auth test1 = new auth();
test1.key = basicAPI_Key;
switch (requestTyp)
{
case 0:
test1.request = "deckList";
break;
case 1:
test1.request = "card";
break;
}
string output = JsonConvert.SerializeObject(test1);
byte[] outputToServer = Encoding.ASCII.GetBytes(output);
//Debug.Log(output);
RestClient.Request(new RequestHelper
{
Uri = basicRequestPage,
Method = "POST",
Timeout = 10,
//EnableDebug = true,
ParseResponseBody = false, //Don't encode and parse downloaded data as JSONe
BodyRaw = outputToServer
}).Then(response =>
{
// EditorUtility.DisplayDialog("Status", response.Text, "Ok");
var rest = response.Text;
//Debug.Log(rest);
outputs = rest.ToString();
//EditorUtility.DisplayDialog("Status", outputs, "Ok");
return outputs;
}).Catch(err =>
{
var error = err as RequestException;
EditorUtility.DisplayDialog("Error Response", error.Response + "", "Ok");
}
);
return ""; //<----- this here
}
Related
This feels like a simple question and I feel like I am overthinking it. I am doing an AWS project that will compare face(s) on an image to a database (s3bucket) of other faces. So far, I have a lambda function for the comparefacerequest, a class library which invokes the function, and an UWP that inputs the image file and outputs a result. It has worked so far being based on boolean (true or false) functions, but now I want it to instead return what face(s) are recognized via an array. I struggling at implementing this.
Below is my lambda function. I have adjusted the task to be an Array instead of a bool and changed the return to be an array. At the bottom, I have created a global variable class with a testing array so I could attempt to reference the array elsewhere.
public class Function
{
//Function
public async Task<Array> FunctionHandler(string input, ILambdaContext context)
{
//number of matched faces
int matched = 0;
//Client setup
var rekognitionclient = new AmazonRekognitionClient();
var s3client = new AmazonS3Client();
//Create list of target images
ListObjectsRequest list = new ListObjectsRequest
{
BucketName = "bucket2"
};
ListObjectsResponse listre = await s3client.ListObjectsAsync(list);
//loop of list
foreach (Amazon.S3.Model.S3Object obj in listre.S3Objects)
{
//face request with input and obj.key images
var comparefacesrequest = new CompareFacesRequest
{
SourceImage = new Image
{
S3Object = new S3Objects
{
Bucket = "bucket1",
Name = input
}
},
TargetImage = new Image
{
S3Object = new S3Objects
{
Bucket = "bucket2",
Name = obj.Key
}
},
};
//compare with confidence of 95 (subject to change) to current target image
var detectresponse = await rekognitionclient.CompareFacesAsync(comparefacesrequest);
detectresponse.FaceMatches.ForEach(match =>
{
ComparedFace face = match.Face;
if (match.Similarity > 95)
{
//if face detected, raise matched
matched++;
for(int i = 0; i < Globaltest.testingarray.Length; i++)
{
if (Globaltest.testingarray[i] == "test")
{
Globaltest.testingarray[i] = obj.Key;
}
}
}
});
}
//Return true or false depending on if it is matched
if (matched > 0)
{
return Globaltest.testingarray;
}
return Globaltest.testingarray;
}
}
public static class Globaltest
{
public static string[] testingarray = { "test", "test", "test" };
}
Next, is my invoke request in my class library. It has so far been based on the lambda outputting a boolean result, but I thought, "hey, it is parsing the result, it should be fine, right"? I do convert the result to a string, as there is no GetArray, from what I know.
public async Task<bool> IsFace(string filePath, string fileName)
{
await UploadS3(filePath, fileName);
AmazonLambdaClient client = new AmazonLambdaClient(accessKey, secretKey, Amazon.RegionEndpoint.USWest2);
InvokeRequest ir = new InvokeRequest();
ir.InvocationType = InvocationType.RequestResponse;
ir.FunctionName = "ImageTesting";
ir.Payload = "\"" + fileName + "\"";
var result = await client.InvokeAsync(ir);
var strResponse = Encoding.ASCII.GetString(result.Payload.ToArray());
if (bool.TryParse(strResponse, out bool result2))
{
return result2;
}
return false;
}
Finally, here is the section of my UWP where I perform the function. I am referencing the lambda client via "using Lambdaclienttest" (name of lamda project, and this is its only instance I use the reference though). When I run my project, I do still get a face detected when it should, but the Globaltest.testingarray[0] is still equal to "test".
var Facedetector = new FaceDetector(Credentials.accesskey, Credentials.secretkey);
try
{
var result = await Facedetector.IsFace(filepath, filename);
if (result)
{
textBox1.Text = "There is a face detected";
textBox2.Text = Globaltest.testingarray[0];
}
else
{
textBox1.Text = "Try Again";
}
}
catch
{
textBox1.Text = "Please use a photo";
}
Does anyone have any suggestions?
I am making a unity game and have one strange situation, which I will try to explain.
Here is my UserCreator class in which I want to return nativeCountry from another class (MySQLCountryManager):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class UserCreator : MonoBehaviour
{
public static PersonModel CreateUser(PersonModel model)
{
CountryModel nativeCountry = new CountryModel();
nativeCountry = MySQLCountryManager.GetCountryByName(model.NativeCountry);
<some other code here....>
}
}
And here is MySQLCountryManager class with GetCountryByName method:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
public class MySQLCountryManager : MonoBehaviour
{
public static CountryModel GetCountryByName(string countryName)
{
CountryModel country = new CountryModel();
WWWForm form = new WWWForm();
form.AddField("CountryName", countryName);
UnityWebRequestAsyncOperation getCountryByName = new UnityWebRequestAsyncOperation();
getCountryByName = UnityWebRequest.Post(WebReguests.getCountryByName, form).SendWebRequest();
List<string> results = new List<string>();
if (getCountryByName.webRequest.isNetworkError || getCountryByName.webRequest.isHttpError)
{
Debug.LogError(getCountryByName.webRequest.error);
}
else
{
var data = getCountryByName.webRequest.downloadHandler.text;
string[] result = data.Split(',');
for (int i = 0; i < result.Length; i++)
{
results.Add(result[i]);
}
int id;
bool idOk;
idOk = int.TryParse(results[0], out id );
if (idOk)
{
country.id = id;
}
country.CountryName = results[1];
byte[] flagBytes = Convert.FromBase64String(results[2]);
country.Flag = flagBytes;
byte[] shapeBytes = Convert.FromBase64String(results[3]);
country.Shape = shapeBytes;
byte[] woP = Convert.FromBase64String(results[4]);
country.WorldPosition = woP;
byte[] coa = Convert.FromBase64String(results[5]);
country.CoatOfArms = coa;
byte[] dishPicBytes = Convert.FromBase64String(results[6]);
country.DishPic = dishPicBytes;
byte[] curiosityBytes = Convert.FromBase64String(results[7]);
country.CuriosityPic = curiosityBytes;
country.Continent = results[8];
country.Population = results[9];
country.Capital = results[10];
country.Language = results[11];
country.Currency = results[12];
country.Religion = results[13];
country.DishName = results[14];
}
return country;
}
Now, the problem is, when I start debugging project in Visual Studio 2019 if I go Step Into on native country in UserCreator and then Step Into in MySQLCountryManager.GetCountryById, code works fine and returns nativeCountry as I expect. But when I go Step Over nativeCountry, it always throws some exceptions, like 'Index was out of range', 'Input string is not in a correct format' etc. And this is happening for all methods with UnityWebRequest called from UserCreator class.
I tried to google for this but nothing useful was found.
Any idea why this is happening?
tl;dr: Sounds like a race condition to me!
While stepping into the method you most probably give the asynchronous request just enough time to actually finish in the background.
I don't see where you are waiting for the results of the asynchronous download.
See the examples of UnityWebRequest.Post => as with any other asynchronous execution you have to wait until the results are actually back.
Usually you would use a Coroutine with callback like e.g.
public static void GetCountryByNameAsync(MonoBehaviour caller, string countryName, Action<CountryModel> whenDone)
{
caller.StartCoroutine(GetCountryByNameRoutine(countryName, whenDone))
}
private static IEnumerator GetCountryByNameRoutine(string countryName, Action<CountryModel> whenDone)
{
var form = new WWWForm();
form.AddField("CountryName", countryName);
using(var request = UnityWebRequest.Post(WebReguests.getCountryByName, form))
{
// WAIT until the request has either failed or succeeded
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.LogError(request.error);
yield break;
}
var data = request.downloadHandler.text;
var results = data.Split(',');
var country = new CountryModel();
if (int.TryParse(results[0], out var id))
{
country.id = id;
}
country.CountryName = results[1];
var flagBytes = Convert.FromBase64String(results[2]);
country.Flag = flagBytes;
var shapeBytes = Convert.FromBase64String(results[3]);
country.Shape = shapeBytes;
var woP = Convert.FromBase64String(results[4]);
country.WorldPosition = woP;
var coa = Convert.FromBase64String(results[5]);
country.CoatOfArms = coa;
var dishPicBytes = Convert.FromBase64String(results[6]);
country.DishPic = dishPicBytes;
var curiosityBytes = Convert.FromBase64String(results[7]);
country.CuriosityPic = curiosityBytes;
country.Continent = results[8];
country.Population = results[9];
country.Capital = results[10];
country.Language = results[11];
country.Currency = results[12];
country.Religion = results[13];
country.DishName = results[14];
whenDone?.Invoke(country);
}
}
then later you would rather use it like e.g.
// caller will be whatever script is actually calling this method
// we will take that reference to make it also responsible for executing the according Coroutine
public static void CreateUserAsync(MonoBehaviour caller, PersonModel model, Action<PersonModel> whenDone)
{
MySQLCountryManager.GetCountryByName(caller, model.NativeCountry, nativeCountry =>
{
<some other code here....>
whenDone?.Invoke(theCreatedPersonModel);
});
}
Or if it gets more complex instead of Coroutines you might rather use an async - await approach and pass the final result back into the Unity main thread.
I have wrapped the C# FCM AdminSDK in a WCF. When I publish the code to my local using debug everything works as expected. When I publish the code using release I get a "Object reference not set to an instance of an object." when attempting to instantiate the "Message" object. Why does this happen?
The exception happens on the line "var fcmMessage = new Message()"
using FirebaseAdmin;
using FirebaseAdmin.Messaging;
using Google.Apis.Auth.OAuth2;
using ID.Service.PushNotification.Enums;
using ID.Service.PushNotification.Models;
using ID.Service.PushNotification.ServiceHelpers;
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Hosting;
namespace ID.Service.PushNotification.Helpers
{
public class FcmHelper
{
readonly static FirebaseApp app = FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile(HostingEnvironment.MapPath(#"~/App_Data/jq4bb-37597f7301.json"))
});
public static void BulkPushNotification(List<EnrolmentModel> enrolments, string message, int messageId, DeepLink path = DeepLink.None)
{
foreach (EnrolmentModel enrolment in enrolments)
{
PushNotification(enrolment, message, messageId, path);
}
}
public static async void PushNotification(EnrolmentModel enrolment, string message, int messageId, DeepLink path = DeepLink.None)
{
try
{
var pathLink = (path != DeepLink.None) ? path.GetPath() : "";
var registrationToken = Encoding.UTF8.GetString(Convert.FromBase64String(enrolment.DeviceToken));
LogHelper.Error("rt: " + registrationToken);
LogHelper.Error("msg: " + message);
LogHelper.Error("pl" + pathLink);
var fcmMessage = new Message()
{
Token = registrationToken,
Android = new AndroidConfig()
{
Notification = new AndroidNotification()
{
Body = message,
Title = "Title",
Sound = "bing"
//ClickAction = "rewards",
//Color = "#CA5151",
//Icon="",
},
Priority = Priority.Normal,
TimeToLive = TimeSpan.FromSeconds(2419200),
//Data = new Dictionary<string, string>()
//{
// { "deepLinkPath", pathLink }
//},
}
};
// Send a message to the device corresponding to the provided
// registration token.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(fcmMessage);
bool successfullySent = false;
if (response.ToLower().Contains("projects/com-app/messages/0:"))
{
successfullySent = true;
}
ResultFeedbackServiceHelper.SaveResultFeedback(
response,
Convert.ToInt32(messageId),
Convert.ToInt32(enrolment.DeviceId),
successfullySent,
new List<string> { enrolment.DeviceToken }
);
}
catch (Exception ex)
{
ResultFeedbackServiceHelper.SaveResultFeedback(
ex.Message,
Convert.ToInt32(messageId),
Convert.ToInt32(enrolment.DeviceId),
false,
new List<string> { enrolment.DeviceToken }
);
LogHelper.Error("Error sending push messages to (fcm) gcn " + ex.ToString());
}
}
}
}
Exception:''2019-03-05 15:09:55,637 Thread:'[13]' Level:'ERROR' Message:'Error sending push messages to (fcm) gcn System.NullReferenceException: Object reference not set to an instance of an object.
at ID.Service.PushNotification.Helpers.FcmHelper.d__2.MoveNext() in D:\BuildAgents\Agent1_work\475\s\PNS\Main\ID.Service.PushNotification\Helpers\FCMHelper.cs:line 49'
I have the following controller:
[Authorize]
public class SetupController : ApiController
{
[HttpPost]
public Task async SetupPartnerPackAsync(SetupInformation info)
{
if (info.SslCertificateGenerate)
{
SetupManager.CreateX509Certificate(info);
}
else
{
SetupManager.LoadX509Certificate(info);
}
info.SslCertificateThumbprint = SetupManager.GetX509CertificateThumbprint(info);
info.AzureAppKeyCredential = SetupManager.GetX509CertificateInformation(info);
await SetupManager.RegisterAzureADApplication(info);
}
}
But I have the following 2 error which seems simple:
Severity Code Description Project File Line Suppression State
Error CS1520 Method must have a return
type InnovationInABoxWebApi H:\InnovationInABoxWebApi\InnovationInABoxWebApi\Controllers\SetupController.cs 24 Active
Severity Code Description Project File Line Suppression State
Error CS4033 The 'await' operator can only be used within an async
method. Consider marking this method with the 'async' modifier and
changing its return type to
'Task'. InnovationInABoxWebApi H:\InnovationInABoxWebApi\InnovationInABoxWebApi\Controllers\SetupController.cs 39 Active
However I am not sure how to fix this, as the operation can take some time to complete, it really needs to be asybnc
and the setupmanager
using CERTENROLLLib;
using Microsoft.Identity.Client;
using Microsoft.Online.SharePoint.TenantAdministration;
using Microsoft.SharePoint.Client;
using Newtonsoft.Json;
using OfficeDevPnP.Core;
using OfficeDevPnP.Core.Entities;
using OfficeDevPnP.Core.Framework.Provisioning.Model;
using OfficeDevPnP.Core.Framework.Provisioning.ObjectHandlers;
using OfficeDevPnP.Core.Framework.Provisioning.Providers.Xml;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Resources;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Xml.Linq;
namespace InnovationInABoxWebApi.Components
{
public static class SetupManager
{
public static String GetX509CertificateThumbprint(SetupInformation info)
{
var certificate = info.AuthenticationCertificate;
return (certificate.Thumbprint.ToUpper());
}
public static String GetX509CertificateInformation(SetupInformation info)
{
// var basePath = String.Format(#"{0}..\..\..\..\Scripts\", AppDomain.CurrentDomain.BaseDirectory);
var certificate = info.AuthenticationCertificate;
//var certificate = new X509Certificate2();
//if (info.SslCertificateGenerate)
//{
// certificate.Import($#"{basePath}{info.SslCertificateCommonName}.cer");
//}
//else
//{
// certificate = new X509Certificate2(info.SslCertificateFile, info.SslCertificatePassword);
//}
var rawCert = certificate.GetRawCertData();
var base64Cert = System.Convert.ToBase64String(rawCert);
var rawCertHash = certificate.GetCertHash();
var base64CertHash = System.Convert.ToBase64String(rawCertHash);
var KeyId = System.Guid.NewGuid().ToString();
var keyCredential =
"{" +
"\"customKeyIdentifier\": \"" + base64CertHash + "\"," +
"\"keyId\": \"" + KeyId + "\"," +
"\"type\": \"AsymmetricX509Cert\"," +
"\"usage\": \"Verify\"," +
"\"key\": \"" + base64Cert + "\"" +
"}";
return (keyCredential);
}
public static void CreateX509Certificate(SetupInformation info)
{
var certificate = CreateSelfSignedCertificate(info.SslCertificateCommonName.ToLower(),
info.SslCertificateStartDate, info.SslCertificateEndDate, info.SslCertificatePassword);
SaveCertificateFiles(info, certificate);
}
public static void LoadX509Certificate(SetupInformation info)
{
var certificate = new X509Certificate2(info.SslCertificateFile, info.SslCertificatePassword);
info.AuthenticationCertificate = certificate;
info.SslCertificateCommonName = certificate.SubjectName.Name;
}
public static void SaveCertificateFiles(SetupInformation info, X509Certificate2 certificate)
{
info.AuthenticationCertificate = certificate;
//var basePath = String.Format(#"{0}..\..\..\..\Scripts\", AppDomain.CurrentDomain.BaseDirectory);
//info.SslCertificateFile = $#"{basePath}{info.SslCertificateCommonName}.pfx";
//var pfx = certificate.Export(X509ContentType.Pfx, info.SslCertificatePassword);
//System.IO.File.WriteAllBytes(info.SslCertificateFile, pfx);
//var cer = certificate.Export(X509ContentType.Cert);
//System.IO.File.WriteAllBytes($#"{basePath}{info.SslCertificateCommonName}.cer", cer);
}
public static X509Certificate2 CreateSelfSignedCertificate(string subjectName, DateTime startDate, DateTime endDate, String password)
{
// Create DistinguishedName for subject and issuer
var name = new CX500DistinguishedName();
name.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_NONE);
// Create a new Private Key for the certificate
CX509PrivateKey privateKey = new CX509PrivateKey();
privateKey.ProviderName = "Microsoft RSA SChannel Cryptographic Provider";
privateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
privateKey.Length = 2048;
privateKey.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)";
privateKey.MachineContext = true;
privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;
privateKey.Create();
// Define the hashing algorithm
var serverauthoid = new CObjectId();
serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // Server Authentication
var ekuoids = new CObjectIds();
ekuoids.Add(serverauthoid);
var ekuext = new CX509ExtensionEnhancedKeyUsage();
ekuext.InitializeEncode(ekuoids);
// Create the self signing request
var cert = new CX509CertificateRequestCertificate();
cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, String.Empty);
cert.Subject = name;
cert.Issuer = cert.Subject;
cert.NotBefore = startDate;
cert.NotAfter = endDate;
cert.X509Extensions.Add((CX509Extension)ekuext);
cert.Encode();
// Enroll the certificate
var enroll = new CX509Enrollment();
enroll.InitializeFromRequest(cert);
string certData = enroll.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64HEADER);
enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
certData, EncodingType.XCN_CRYPT_STRING_BASE64HEADER, String.Empty);
var base64encoded = enroll.CreatePFX(password, PFXExportOptions.PFXExportChainWithRoot);
// Instantiate the target class with the PKCS#12 data
return new X509Certificate2(
System.Convert.FromBase64String(base64encoded), password,
System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable);
}
public async static Task RegisterAzureADApplication(SetupInformation info)
{
// Fix the App URL
if (!info.AzureWebAppUrl.EndsWith("/"))
{
info.AzureWebAppUrl = info.AzureWebAppUrl + "/";
}
// Load the App Manifest template
//Stream stream = typeof(SetupManager)
// .Assembly
// .GetManifestResourceStream("OfficeDevPnP.PartnerPack.Setup.Resources.azure-ad-app-manifest.json");
using (StreamReader sr = new StreamReader("Resources\azure-ad-app-manifest.json"))
{
// Get the JSON manifest
var jsonApplication = sr.ReadToEnd();
var application = JsonConvert.DeserializeObject<AzureAdApplication>(jsonApplication);
var keyCredential = JsonConvert.DeserializeObject<KeyCredential>(info.AzureAppKeyCredential);
application.displayName = info.ApplicationName;
application.homepage = info.AzureWebAppUrl;
application.identifierUris = new List<String>();
application.identifierUris.Add(info.ApplicationUniqueUri);
application.keyCredentials = new List<KeyCredential>();
application.keyCredentials.Add(keyCredential);
application.replyUrls = new List<String>();
application.replyUrls.Add(info.AzureWebAppUrl);
// Generate the Application Shared Secret
var startDate = DateTime.Now;
Byte[] bytes = new Byte[32];
using (var rand = System.Security.Cryptography.RandomNumberGenerator.Create())
{
rand.GetBytes(bytes);
}
info.AzureAppSharedSecret = System.Convert.ToBase64String(bytes);
application.passwordCredentials = new List<object>();
application.passwordCredentials.Add(new AzureAdApplicationPasswordCredential
{
CustomKeyIdentifier = null,
StartDate = startDate.ToString("o"),
EndDate = startDate.AddYears(2).ToString("o"),
KeyId = Guid.NewGuid().ToString(),
Value = info.AzureAppSharedSecret,
});
// Get an Access Token to create the application via Microsoft Graph
var office365AzureADAccessToken = await AzureManagementUtility.GetAccessTokenSilentAsync(
AzureManagementUtility.MicrosoftGraphResourceId,
ConfigurationManager.AppSettings["O365:ClientId"]);
var azureAdApplicationCreated = false;
// Create the Azure AD Application
try
{
await CreateAzureADApplication(info, application, office365AzureADAccessToken);
azureAdApplicationCreated = true;
}
catch (ApplicationException ex)
{
var graphError = JsonConvert.DeserializeObject<GraphError>(((HttpException)ex.InnerException).Message);
if (graphError != null && graphError.error.code == "Request_BadRequest" &&
graphError.error.message.Contains("identifierUris already exists"))
{
// We need to remove the existing application
// Thus, retrieve it
String jsonApplications = await HttpHelper.MakeGetRequestForStringAsync(
String.Format("{0}applications?$filter=identifierUris/any(c:c+eq+'{1}')",
AzureManagementUtility.MicrosoftGraphBetaBaseUri,
HttpUtility.UrlEncode(info.ApplicationUniqueUri)),
office365AzureADAccessToken);
var applications = JsonConvert.DeserializeObject<AzureAdApplications>(jsonApplications);
var applicationToUpdate = applications.Applications.FirstOrDefault();
if (applicationToUpdate != null)
{
// Remove it
await HttpHelper.MakeDeleteRequestAsync(
String.Format("{0}applications/{1}",
AzureManagementUtility.MicrosoftGraphBetaBaseUri,
applicationToUpdate.Id),
office365AzureADAccessToken);
// And add it again
await CreateAzureADApplication(info, application, office365AzureADAccessToken);
azureAdApplicationCreated = true;
}
}
}
if (azureAdApplicationCreated)
{
// TODO: We should upload the logo
// property mainLogo: stream of the application via PATCH
}
}
}
public static async Task CreateAzureADApplication(SetupInformation info, AzureAdApplication application, string office365AzureADAccessToken)
{
String jsonResponse = await HttpHelper.MakePostRequestForStringAsync(
String.Format("{0}applications",
AzureManagementUtility.MicrosoftGraphBetaBaseUri),
application,
"application/json", office365AzureADAccessToken);
var azureAdApplication = JsonConvert.DeserializeObject<AzureAdApplication>(jsonResponse);
info.AzureAppClientId = azureAdApplication.AppId.HasValue ? azureAdApplication.AppId.Value : Guid.Empty;
}
}
}
You are defining the method with async word after the return type Task, async must be before Task.
public async Task SetupPartnerPackAsync(SetupInformation info)
{
.
.
.
I'm building a simple application that requires login. At the moment I'm connecting to my database directly from my C# application however, the college network on which this will be used doesn't allow direct connections to MySQL for some reason. I decided to take a look at how I would do this from PHP instead. I've build a simple login form and tested it and it seems to work. However I have some questions and issues that need sorting out.
How would I first of all stop just anyone typing in the address of the PHP file and getting the data back?
Second, how will I be able to get multiple results back? Let's say I make a PHP file that gets all of the user's files and stores them in the C# application, how do I actually parse this from the PHP file?
Here is an example of a login.php file I would have on the server:
<?php
include("connect.php");
$username = mysql_escape_string($_GET['username']);
$password = mysql_escape_string($_GET['password']);
$squery = mysql_query("SELECT * FROM users WHERE username='$username'");
$query = mysql_fetch_array($squery);
$rowcount = mysql_num_rows($squery);
if($rowcount == 1)
{
if($password != $query['password'])
echo'Password errata';
else
echo 'Login avvenuto';
}
else
echo 'Account non registrato';
?>
And here is the code I'd use on C# to access the PHP file:
string Reply = new WebClient().DownloadString("http://127.0.0.1/ClipCloud.Service/account_auth/login.php?username=" + textBox1.Text + "&password=" + textBox2.Text);
switch (Reply.ToLower())
{
case "account non registrato":
{
MessageBox.Show("Account not registered!");
break;
}
case "password errata":
{
MessageBox.Show("Password error!");
break;
}
case "login avvenuto":
{
MessageBox.Show("Login happened!");
break;
}
default:
{
MessageBox.Show("Error with the remote server, please let try again later!");
break;
}
}
Sorry if this question is a bit confusing, I basically just need to know how to correctly manipulate a database with PHP using C# with correct security in place.
You can get C# communicating with PHP by implementing a simple JSON API Server.
Conside the following : http://yoursite.com/api_server.php
api_server.php
<?php
// Load Request
$api_method = isset($_POST['api_method']) ? $_POST['api_method'] : '';
$api_data = isset($_POST['api_data']) ? $_POST['api_data'] : '';
// Validate Request
if (empty($api_method) || empty($api_data)) {
API_Response(true, 'Invalid Request');
}
if (!function_exists($api_method)) {
API_Response(true, 'API Method Not Implemented');
}
// Call API Method
call_user_func($api_method, $api_data);
/* Helper Function */
function API_Response($isError, $errorMessage, $responseData = '')
{
exit(json_encode(array(
'IsError' => $isError,
'ErrorMessage' => $errorMessage,
'ResponseData' => $responseData
)));
}
/* API Methods */
function loginUser($api_data)
{
// Decode Login Data
$login_data = json_decode($api_data);
// Dummy Check
if ($login_data->username == 'test' &&
$login_data->password == '1234')
{
// Success
API_Response(false, '', 'SUCCESS');
}
else
{
// Error
API_Response(true, 'Invalid username and/or password.');
}
}
?>
Then you communicate with it via C# like this, making POST Requests:
using (var wb = new WebClient())
{
var data = new NameValueCollection();
data["api_method"] = "loginUser";
data["api_data"] = "{ \"username\":\"test\", \"password\":\"1234\" }";
var responseBytes = wb.UploadValues(
"http://yoursite.com/api_server.php", "POST", data);
string responseString = Encoding.Default.GetString(responseBytes);
}
Here, the responseString from the API server will the json string. To decode this, you can use this: http://james.newtonking.com/json
Here's a fully working example of how everything is put together in the C# app using a simple console app:
Note how I am generating json string (for api_data) via the json library, instead of manually typing it.
using System;
using System.Text;
using System.Net;
using System.Collections.Specialized;
using Newtonsoft.Json;
namespace TemplateFive
{
public class API_Response
{
public bool IsError { get; set; }
public string ErrorMessage { get; set; }
public string ResponseData { get; set; }
}
public class Login_Request
{
public string username { get; set; }
public string password { get; set; }
}
class Program
{
static void Main(string[] args)
{
// request params
string apiUrl = "https://yoursite.com/api_server.php";
string apiMethod = "loginUser";
Login_Request myLogin_Request = new Login_Request()
{
username = "test",
password = "1234"
};
// make http post request
string response = Http.Post(apiUrl, new NameValueCollection()
{
{ "api_method", apiMethod },
{ "api_data", JsonConvert.SerializeObject(myLogin_Request) }
});
// decode json string to dto object
API_Response r =
JsonConvert.DeserializeObject<API_Response>(response);
// check response
if (!r.IsError && r.ResponseData == "SUCCESS")
{
Console.WriteLine("login success");
}
else
{
Console.WriteLine("login error, reason is: {0}",
r.ErrorMessage);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
public static class Http
{
public static String Post(string uri, NameValueCollection pairs)
{
byte[] response = null;
using (WebClient client = new WebClient())
{
response = client.UploadValues(uri, pairs);
}
return Encoding.Default.GetString(response);
}
}
}
finally, to secure the whole thing, run your site under SSL, so you'd access the api server via this URL: https://yoursite.com/api_server.php
Here's me testing the API server locally using a RESTClient pluggin on firefox.
Success Scenario: http://i.imgur.com/sw5yxvE.png
Error Scenario: http://i.imgur.com/HHmHlWX.png
The Solution is: remove the BOM :-)
static class Http
{
public static String Post(string uri, NameValueCollection pairs)
{
byte[] response = null;
using (WebClient client = new WebClient())
{
response = client.UploadValues(uri, pairs);
}
string ret = Encoding.UTF8.GetString(response);
ret = ret.Trim(new char[] { '\uFEFF', '\u200B' });//removes the BOM
return ret;
}
}