Azure Function Runs Locally But Not On Azure - c#

My function is running locally but when I publish it to Azure it is erroring.
The error is
Value cannot be null. Parameter name: format
Googling this seems to suggest the input to the function is wrong but I am posting the exact same JSON that allows it to run locally.
I am lost to how I fix this. Any ideas?
Code below
using System;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;
namespace MyFunction
{
public static class Login
{
[FunctionName("Login")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, ILogger log)
{
Boolean websiteEnabled = false;
Guid contactId = new Guid();
log.LogInformation("C# HTTP trigger function processed a request.");
dynamic data = await req.Content.ReadAsAsync<object>();
string username = data?.username;
string password = data?.password;
string passwordHash = "";
User user = new User();
OrganizationServiceProxy _serviceProxy;
IOrganizationService _service;
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.UserName.UserName = ConfigurationManager.AppSettings["OrganisationUsername"];
clientCredentials.UserName.Password = ConfigurationManager.AppSettings["OrganisationPassword"];
Uri organisationUri = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
Uri realm = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
using (_serviceProxy = new OrganizationServiceProxy(organisationUri, realm, clientCredentials, null))
{
_serviceProxy.EnableProxyTypes();
_service = (IOrganizationService)_serviceProxy;
QueryByAttribute querybyattribute = new QueryByAttribute("contact");
querybyattribute.ColumnSet = new ColumnSet("cbob_websitepassword","cbob_websiteenabled","contactid","fullname", "parentcustomerid");
querybyattribute.Attributes.AddRange("emailaddress1");
querybyattribute.Values.AddRange(username);
EntityCollection retrieved = _service.RetrieveMultiple(querybyattribute);
if(retrieved.Entities.Count == 1)
{
passwordHash = retrieved.Entities[0].GetAttributeValue<String>("cbob_websitepassword");
websiteEnabled = retrieved.Entities[0].GetAttributeValue<Boolean>("cbob_websiteenabled");
contactId = retrieved.Entities[0].GetAttributeValue<Guid>("contactid");
user.Account = retrieved.Entities[0].GetAttributeValue<EntityReference>("parentcustomerid").Name.ToString();
user.Email = username;
user.LoggedInUser = retrieved.Entities[0].GetAttributeValue<String>("fullname");
user.AccountID = retrieved.Entities[0].GetAttributeValue<EntityReference>("parentcustomerid").Id.ToString();
user.BookingID = retrieved.Entities[0].Id.ToString();
} else
{
return req.CreateResponse(HttpStatusCode.BadRequest, "Not allowed");
}
}
Boolean hash = bCryptHash(passwordHash, contactId.ToString() + "-" + password);
Console.WriteLine(hash);
if (!websiteEnabled)
{
return req.CreateResponse(HttpStatusCode.BadRequest, "Not allowed");
}
if (hash)
{
string output = JsonConvert.SerializeObject(user).ToString();
return req.CreateResponse(HttpStatusCode.OK, output);
} else
{
return req.CreateResponse(HttpStatusCode.BadRequest, "Not allowed");
}
}
public static Boolean bCryptHash(string hash, string submitted)
{
Boolean hashPassword = BCrypt.Net.BCrypt.Verify(submitted,hash);
return hashPassword;
}
public static String sha256_hash(string value)
{
StringBuilder Sb = new StringBuilder();
using (var hash = SHA256.Create())
{
Encoding enc = Encoding.UTF8;
Byte[] result = hash.ComputeHash(enc.GetBytes(value));
foreach (Byte b in result)
Sb.Append(b.ToString("x2"));
}
return Sb.ToString();
}
}
}

Uri organisationUri = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
Uri realm = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
My guess is that one or both of those lines may be the problem. You are using String.Format here where the first parameter is the format parameter. The AppSettings you are providing for that parameter seem to be unavailable. Make sure you have those configuration values available when you deploy your function.
Additionally: If you don't provide any objects to the String.Format that get inserted in the String, why are you using it at all?

Make sure you have added those local app settings (i.e OrganisationUsername and so on in local.settings.json file) to Application settings. Find it in Azure portal, Platform features> Application settings. When we publish Function project to Azure, it's by design that content in local.settings.json is not published because it's designed for local dev.
When we publish Functions with VS, there's a friendly dialog to update Application settings.

Related

How to generate a hash for my Android app?

I'm using this guide to implement an autocomplete funcionality in an app I'm working on, but when I try to test it in different computers it returns me a different hash https://www.c-sharpcorner.com/article/verify-otp-automatically-in-android-without-sms-read-permission-using-xamarin-fo/
The helper class used is the following:
using System.Text;
using Android.Content;
using Android.Content.PM;
using Android.Util;
using Java.Security;
using Java.Util;
namespace InteliMobile.App.Droid.Service
{
public class AppHashKeyHelper
{
private static string HASH_TYPE = "SHA-256";
private static int NUM_HASHED_BYTES = 9;
private static int NUM_BASE64_CHAR = 11;
private static string GetPackageSignature(Context context)
{
var packageManager = context.PackageManager;
var signatures = packageManager.GetPackageInfo(context.PackageName, PackageInfoFlags.Signatures).Signatures;
return signatures.First().ToCharsString();
}
public static string GetAppHashKey(Context context)
{
string keystoreHexSignature = GetPackageSignature(context);
string appInfo = context.PackageName + " " + keystoreHexSignature;
try
{
var messageDigest = MessageDigest.GetInstance(HASH_TYPE);
messageDigest.Update(Encoding.UTF8.GetBytes(appInfo));
byte[] hashSignature = messageDigest.Digest();
hashSignature = Arrays.CopyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
string base64Hash = Android.Util.Base64.EncodeToString(hashSignature, Base64Flags.NoPadding | Base64Flags.NoWrap);
base64Hash = base64Hash.Substring(0, NUM_BASE64_CHAR);
return base64Hash;
}
catch (NoSuchAlgorithmException e)
{
return null;
}
}
}
}
How can I get the hash without using a bash script, since the server runs in a Windows machine? Is it safe to deploy the app to production with the helper class in it?
You don't compute the hash client side. It's sent from the server, and the instructions to do so are at https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string
You don't do it in code at all, you do it via command line tools.

Azure Function HTTP gets executed multiple times on a single execution

I have a relatively simple Azure Function running under the consumption plan with a timeout setting of 4 four minutes.
When I execute through the portal it gets executed multiple times with runs overlapping each other, even though I had executed it just once.
For example:
Execution 1
00:36:52.917
00:41:25.750
Execution 2
00:40:41.793
00:41:25.700
Execution 3
00:44:27.430
00:48:30.857
There's no logic as to the multiple and overlapping execution times.
Any idea what is going on?
using System;
using System.Threading.Tasks;
using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.IO;
using Microsoft.Data.SqlClient;
namespace FMPApiCall
{
public static class FMPTestAPI
{
#region Private Data Members
private static readonly HttpClient Client = new HttpClient();
#endregion
[FunctionName("FMPTestAPI")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
HttpRequest req, ILogger log)
{
log.LogInformation("FMPTestAPI triggered - BEGIN");
List<string> symbolsList = FMPCallAPI.CommonFunctions.GetSymbolsFromDB(); //gets as list of IDs from the database
int counter = 0;
using SqlConnection dbconnection = new SqlConnection(Environment.GetEnvironmentVariable("SqlServerConnectionString"));
{
dbconnection.Open();
foreach (string symbol in symbolsList)
{
counter++;
var apiRequest =
$"https://myapi.com/api/v3/dataset1/{symbol}?period=quarter&limit=4&apikey=123";
var response = await Client.GetAsync(apiRequest);
var symbolsData = await response.Content.ReadAsStringAsync();
var sqlStr = $"INSERT INTO [dbo].[_azure] (symbol,runid, response,lastupdated) VALUES ( '{symbol}' , {counter} ,'{response}', getutcdate() )";
using (SqlCommand cmd = new SqlCommand(sqlStr, dbconnection))
{
var rows = cmd.ExecuteNonQuery();
}
}
dbconnection.Close();
}
log.LogInformation("FMPTestAPI triggered - END");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult(new { Hello = name })
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
}
eee

How to read Brave Browser cookie database encrypted values in C# (.NET Core)?

I am attempting to read the encrypted values of cookies using a C# console app.
My cookie reader class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp1.Models
{
public class ChromeCookieReader
{
public IEnumerable<Tuple<string, string>> ReadCookies(string hostName)
{
if (hostName == null) throw new ArgumentNullException("hostName");
using var context = new ChromeCookieDbContext();
var cookies = context
.Cookies
.Where(c => c.HostKey.Equals("localhost"))
.AsNoTracking();
foreach (var cookie in cookies)
{
var decodedData = ProtectedData
.Unprotect(cookie.EncryptedValue,
null,
DataProtectionScope.CurrentUser);
var decodedValue = Encoding.UTF8.GetString(decodedData);
yield return Tuple.Create(cookie.Name, decodedValue);
}
}
}
}
My EF DbContext
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp1.Models
{
public class Cookie
{
[Column("host_key")]
public string HostKey { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("encrypted_value")]
public byte[] EncryptedValue { get; set; }
}
public class ChromeCookieDbContext : DbContext
{
public DbSet<Cookie> Cookies { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// var dbPath = Environment.GetFolderPath(
// Environment.SpecialFolder.LocalApplicationData)
// + #"\Google\Chrome\User Data\Default\Cookies";
var dbPath = Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData)
+ #"\BraveSoftware\Brave-Browser\User Data\Default\Cookies";
if (!System.IO.File.Exists(dbPath)) throw new System.IO.FileNotFoundException("Cant find cookie store", dbPath); // race condition, but i'll risk it
var connectionString = "Data Source=" + dbPath + ";Mode=ReadOnly;";
optionsBuilder
.UseSqlite(connectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Cookie>().ToTable("cookies").HasNoKey();
}
}
}
My attempted solution was inspired by Encrypted cookies in Chrome however it doesn't look like it'll work the same despite Brave Browser being based on Chromium. Instead the Windows Data Protection API throws an exception.
Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException
HResult=0x0000000D
Message=The data is invalid.
Source=System.Security.Cryptography.ProtectedData
StackTrace:
at System.Security.Cryptography.ProtectedData.ProtectOrUnprotect(Byte[] inputData, Byte[] optionalEntropy, DataProtectionScope scope, Boolean protect)
at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
at ConsoleApp1.Models.ChromeCookieReader.<ReadCookies>d__0.MoveNext()
Other known issues: If Brave is open EF Core "freaks out" that the SQLite database is locked and won't read anything.
In Chromium version 80 and up, Google modified the way that cookies are encrypted to provide additional security to users. You cannot pass cookies to the Windows DPAPI directly for decryption anymore. Rather Chrome's Local State stores an encryption key that is decrypted with the Windows DPAI, you have to use that key to decrypt the cookies. I am giving credit where it's due as I did not find this out on my own and used information from the answer at https://stackoverflow.com/a/60611673/6481581 to fix my issue.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using System.Security.Cryptography;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
namespace BraveBrowserCookieReaderDemo
{
public class BraveCookieReader
{
public IEnumerable<Tuple<string, string>> ReadCookies(string hostName)
{
if (hostName == null) throw new ArgumentNullException("hostName");
using var context = new BraveCookieDbContext();
var cookies = context
.Cookies
.Where(c => c.HostKey.Equals(hostName))
.AsNoTracking();
// Big thanks to https://stackoverflow.com/a/60611673/6481581 for answering how Chrome 80 and up changed the way cookies are encrypted.
string encKey = File.ReadAllText(System.Environment.GetEnvironmentVariable("LOCALAPPDATA") + #"\BraveSoftware\Brave-Browser\User Data\Local State");
encKey = JObject.Parse(encKey)["os_crypt"]["encrypted_key"].ToString();
var decodedKey = System.Security.Cryptography.ProtectedData.Unprotect(Convert.FromBase64String(encKey).Skip(5).ToArray(), null, System.Security.Cryptography.DataProtectionScope.LocalMachine);
foreach (var cookie in cookies)
{
var data = cookie.EncryptedValue;
var decodedValue = _decryptWithKey(data, decodedKey, 3);
yield return Tuple.Create(cookie.Name, decodedValue);
}
}
private string _decryptWithKey(byte[] message, byte[] key, int nonSecretPayloadLength)
{
const int KEY_BIT_SIZE = 256;
const int MAC_BIT_SIZE = 128;
const int NONCE_BIT_SIZE = 96;
if (key == null || key.Length != KEY_BIT_SIZE / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KEY_BIT_SIZE), "key");
if (message == null || message.Length == 0)
throw new ArgumentException("Message required!", "message");
using (var cipherStream = new MemoryStream(message))
using (var cipherReader = new BinaryReader(cipherStream))
{
var nonSecretPayload = cipherReader.ReadBytes(nonSecretPayloadLength);
var nonce = cipherReader.ReadBytes(NONCE_BIT_SIZE / 8);
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce);
cipher.Init(false, parameters);
var cipherText = cipherReader.ReadBytes(message.Length);
var plainText = new byte[cipher.GetOutputSize(cipherText.Length)];
try
{
var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
cipher.DoFinal(plainText, len);
}
catch (InvalidCipherTextException)
{
return null;
}
return Encoding.Default.GetString(plainText);
}
}
}
}

Downloading file from MS teams programatically

Previously, I developed an application which downloaded a file from a corporate Sharepoint site and then performed some magic with it.
The powers that be have since migrated to MS Teams and I'm trying to update the application to use the new platform. However, I'm having all sorts of issues getting the file to download.
My old (working for Sharepoint) code uses a WebClient to retrieve the file based on credentials previously provided by the user:
private string GetSchedule(string username, string password, string domain)
{
string tempPath = Path.GetTempFileName().Replace(".tmp", ".xlsm");
using (WebClient client = new WebClient())
{
client.Credentials = new NetworkCredential(username, password, domain);
try
{
client.DownloadFile(_networkSchedulePath, tempPath);
}
catch (WebException e)
{
if (e.Message.Contains("401"))
{
StatusUpdated?.Invoke(this, new EventArgs<string>("Invalid Credentials Provided"));
Finished?.Invoke(this, null);
return null;
}
if (e.Message.Contains("404"))
{
StatusUpdated?.Invoke(this, new EventArgs<string>("File Not Found"));
Finished?.Invoke(this, null);
return null;
}
else
{
StatusUpdated?.Invoke(this, new EventArgs<string>(e.Message));
Finished?.Invoke(this, null);
return null;
}
}
}
return tempPath;
}
However, when I use this with the new teams link I'm getting a 403 Forbidden error. So is there any way to programmatically retrieve a file from MS Teams?
I was mistaken in the comments. Simply replacing the NetworkCredentials with SharePointOnlineCredentials is not the solution.
I'm not sure if the following is the "right" approach, but it works and seems pretty solid. Please give it a try:
private static string GetFile(string path, string username, string password, string domain)
{
var secureString = new SecureString();
foreach (var ch in password)
{
secureString.AppendChar(ch);
}
string tempPath = Path.GetTempFileName().Replace(".tmp", ".xlsm");
using (WebClient client = new WebClient())
{
var credentials = new SharePointOnlineCredentials(username, secureString);
client.Headers[HttpRequestHeader.Cookie] = credentials.GetAuthenticationCookie(new Uri(path));
try
{
client.DownloadFile(path, tempPath);
}
catch (WebException e)
{
// Error Handling
}
}
return tempPath;
}
Another option is to use the CSOM rather than using a webclient directly. n.b., I encountered errors at the OpenBinaryDirect() call when using the Microsoft.SharePoint.Client NuGet package and it looks like this package is wildly out of date. It appears that the one to use now is Microsoft.SharePointOnline.CSOM or Microsoft.SharePoint2019.CSOM:
private static string GetFileWithClientContext(string path, string username, string password, string domain)
{
var secureString = new SecureString();
foreach (var ch in password)
{
secureString.AppendChar(ch);
}
string tempPath = Path.GetTempFileName().Replace(".tmp", Path.GetExtension(path));
using (var context = new ClientContext(path))
{
context.Credentials = new SharePointOnlineCredentials(username, secureString);
try
{
using (var file = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, new Uri(path).AbsolutePath))
using (var outFile = System.IO.File.OpenWrite(tempPath))
{
file.Stream.CopyTo(outFile);
}
}
catch (WebException e)
{
// Error Handling
}
}
return tempPath;
}
Thanks to JLRishe for the help his answer and comments provided. However, the final solution varied from the one in his answer, which is why I'm posting it here:
The OfficeDevPnP.Core package is used extensively for this.
Firstly, the AuthenticationManager is used to get a ClientContext in terms of the specific sharepoint site that needs to be accessed. This pops a window up to allow for the MFA. Then various components are loaded in via the ClientContext object. From here, the file is fetched via Guid and dumped to disk.
private string GetSchedule()
{
string tempPath = Path.GetTempFileName().Replace(".tmp", ".xlsm");
try
{
AuthenticationManager authManager = new OfficeDevPnP.Core.AuthenticationManager();
ClientContext ctx = authManager.GetWebLoginClientContext("https://oursite.sharepoint.com/sites/ourspecificsite/");
Web web = ctx.Web;
Microsoft.SharePoint.Client.File schedule = web.GetFileById(new Guid("ourguid"));
ctx.Load(web);
ctx.Load(schedule);
ctx.ExecuteQuery();
FileInformation fInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx, schedule.ServerRelativeUrl);
using (var fileStream = File.Create(tempPath))
{
fInfo.Stream.CopyTo(fileStream);
}
}
catch (WebException e)
{
StatusUpdated?.Invoke(this, new EventArgs<string>(e.Message));
return null;
}
return tempPath;
}
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
using System.IO;
using System.Linq;
namespace Answer
{
class Answer
{
static void Main(string[] args)
{
// Create Confidential Application
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("<My_Azure_Application_Client_ID>")
.WithTenantId("<My_Azure_Tenant_ID>")
.WithClientSecret("<My_Azure_Application_Client_Secret>")
.Build();
// Create an authentication provider.
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
// Configure GraphServiceClient with provider.
GraphServiceClient graphServiceClient = new GraphServiceClient(authenticationProvider);
// Get a user
var user = graphServiceClient.Users["<My_Azure_User_Name>"].Request().GetAsync().Result;
// Get the teams the user is member of
var joinedTeams = graphServiceClient.Users[user.Id].JoinedTeams.Request().GetAsync().Result;
// Get the team we are intereseted in
var team1 = joinedTeams.FirstOrDefault(t => t.DisplayName == "<TeamName_Of_Interest>");
// Get the main folders
var folders = graphServiceClient.Groups[team1.Id].Drive.Root.Children
.Request()
.GetAsync().Result;
// Get the files in the first main folder
var files = graphServiceClient.Groups[team1.Id].Drive.Items[folders[0].Id].Children
.Request()
.GetAsync().Result;
// Get the file-Data of the first file
MemoryStream fileData = graphServiceClient.Groups[team1.Id].Drive.Items[files[0].Id].Content
.Request()
.GetAsync().Result as MemoryStream;
// Save the file to the hard-disc
System.IO.File.WriteAllBytes($"C:\\{files[0].Name}", fileData.ToArray());
}
}
}

How to use quick book invoice api in asp.net

I have a requirement to integerate Quickbook api with my web application. I just created a sample application to accomplish it. I am strange to this I really dont have any idea about how to connect the api or to consume the api.I have mentioned the codes that i have took from ("https://developer.intuit.com/").
I tried by creating an app in the app manager, I have atttached the image FYR. After entering all those details i am not getting "accessTokenSecret" value. Here i just entered the apptoken valuea as accessToken value. Iam getting exception as "Unauthorized" in the service context line. Help me on this.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Intuit.Ipp.Core;
using Intuit.Ipp.Services;
using Intuit.Ipp.Data;
using Intuit.Ipp.Utility;
using Intuit.Ipp.Security;
using Intuit.Ipp.Data.Qbo;
using Newtonsoft.Json;
namespace QuickBookApiConsumption
{
public partial class Invoice : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnsendInvoiceDetails_Click(object sender, EventArgs e)
{
string accessToke = "";
string appToken = "297db54bb5526b494dba97fb2a41063192cd";
string accessTokenSecret = "297db54bb5526b494dba97fb2a41063192cd";
string consumerKey = "qyprdMSG1YHpCPSlWQZTiKVc78dywR";
string consumerSecret = "JPfXE17YnCPGU9m9vuXkF2M765bDb7blhcLB7HeF";
string companyID = "812947125";
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(appToken, accessTokenSecret, consumerKey, consumerSecret);
ServiceContext context = new ServiceContext(oauthValidator, appToken, companyID, IntuitServicesType.QBO);
DataServices service = new DataServices(context);
Invoice os = new Invoice();
Intuit.Ipp.Data.Qbo.InvoiceHeader o = new Intuit.Ipp.Data.Qbo.InvoiceHeader();
o.CustomerName = "Viki";
o.CustomerId = new Intuit.Ipp.Data.Qbo.IdType { Value = "12" };
o.ShipMethodName = "Email";
o.SubTotalAmt = 3.00m;
o.TotalAmt = 6.00m;
o.ShipAddr = new Intuit.Ipp.Data.Qbo.PhysicalAddress { City = "Chni" };
}
}
}
Image:
You should check if you are using correct BASE URL
https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/v2/0400_quickbooks_online/0100_calling_data_services/0010_getting_the_base_url
Using some RESTClient[ ex - RestClient plugin of mozilla browser], verify the OAuth tokens.
Header(content-type) config window.
You can use the following
public void ConnectUsingAuth()
{
string accessToken = ConfigurationManager.AppSettings["AccessTokenQBD"];
string accessTokenSecret = ConfigurationManager.AppSettings["access-secret"];
string consumerKey = ConfigurationManager.AppSettings["consumerKey"];
string consumerKeySecret = ConfigurationManager.AppSettings["consumerSecret"];
string URI = "https://apiend-point";
WebRequest webRequest = WebRequest.Create(URI);
webRequest.Headers.Add("ContentType", "text/xml");
OAuthRequestValidator target = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerKeySecret);
}
Or [ Better option ] You can download the sample program from github and configure the web.config(with proper consumer key and secret)
https://developer.intuit.com/docs/0025_quickbooksapi/0055_devkits/sample_code
You can test all these API endpoints using APIExplorer tool.
Docs - https://developer.intuit.com/docs/0025_quickbooksapi/0010_getting_started/0007_firstrequest
ApiExplorer - https://developer.intuit.com/apiexplorer?apiname=V2QBO
Thanks

Categories