c# - 有没有一种方法可以调用从快速手册中检索公司信息的 API
问题描述
我是 mvc 新手,试图从 Quickbooks 调用 Api 以获取公司信息(沙盒),我按照 intuit.com 中的说明进行操作:创建应用程序、生成客户端 ID、客户端密码并在 web.config 中使用它们。我还生成了 OAuth2,并且在使用用户名和密码登录后,我能够在我的项目中看到“连接到 Quickbooks”对话框,现在我试图调用 Api,所以首先我创建了 OAuth2RequestValidator 类的 dobject,但错误显示“对象引用未设置为对象的实例'我正在使用声明进行身份验证我认为claimsPrincipal 无法从 ClaimsIdentity 读取声明并且我被困在这里,我正在尝试使用 intuit.com 中的示例代码
这是获取身份验证并调用 api 的控制器
public class AppController : Controller
{
public static string clientid = ConfigurationManager.AppSettings["clientid"];
public static string clientsecret = ConfigurationManager.AppSettings["clientsecret"];
public static string redirectUrl = ConfigurationManager.AppSettings["redirectUrl"];
public static string environment = ConfigurationManager.AppSettings["appEnvironment"];
public static OAuth2Client auth2Client = new OAuth2Client(clientid, clientsecret, redirectUrl, environment);
/// <summary>
/// Use the Index page of App controller to get all endpoints from discovery url
/// </summary>
public ActionResult Index()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Session.Clear();
Session.Abandon();
Request.GetOwinContext().Authentication.SignOut("Cookies");
return View();
}
/// <summary>
/// Start Auth flow
/// </summary>
public ActionResult InitiateAuth(string submitButton)
{
switch (submitButton)
{
case "Connect to QuickBooks":
List<OidcScopes> scopes = new List<OidcScopes>();
scopes.Add(OidcScopes.Accounting);
string authorizeUrl = auth2Client.GetAuthorizationURL(scopes);
return Redirect(authorizeUrl);
default:
return (View());
}
}
/// <summary>
/// QBO API Request
/// </summary>
public ActionResult ApiCallService()
{
if (Session["realmId"] != null)
{
string realmId = Session["realmId"].ToString();
try
{
var principal = User as ClaimsPrincipal;
OAuth2RequestValidator oauthValidator = new OAuth2RequestValidator(principal.FindFirst("access_token").Value);
// Create a ServiceContext with Auth tokens and realmId
ServiceContext serviceContext = new ServiceContext(realmId, IntuitServicesType.QBO, oauthValidator);
serviceContext.IppConfiguration.MinorVersion.Qbo = "23";
// Create a QuickBooks QueryService using ServiceContext
QueryService<CompanyInfo> querySvc = new QueryService<CompanyInfo>(serviceContext);
CompanyInfo companyInfo = querySvc.ExecuteIdsQuery("SELECT * FROM CompanyInfo").FirstOrDefault();
string output = "Company Name: " + companyInfo.CompanyName + " Company Address: " + companyInfo.CompanyAddr.Line1 + ", " + companyInfo.CompanyAddr.City + ", " + companyInfo.CompanyAddr.Country + " " + companyInfo.CompanyAddr.PostalCode;
return View("ApiCallService", (object)("QBO API call Successful!! Response: " + output));
}
catch (Exception ex)
{
return View("ApiCallService", (object)("QBO API call Failed!" + " Error message: " + ex.Message));
}
}
else
return View("ApiCallService", (object)"QBO API call Failed!");
}
/// <summary>
/// Use the Index page of App controller to get all endpoints from discovery url
/// </summary>
public ActionResult Error()
{
return View("Error");
}
/// <summary>
/// Action that takes redirection from Callback URL
/// </summary>
public ActionResult Tokens()
{
return View("Tokens");
}
这个控制器创建了访问令牌和刷新令牌
public class CallbackController : Controller
{
/// <summary>
/// Code and realmid/company id recieved on Index page after redirect is complete from Authorization url
/// </summary>
public async Task<ActionResult> Index()
{
//Sync the state info and update if it is not the same
var state = Request.QueryString["state"];
if (state.Equals(AppController.auth2Client.CSRFToken, StringComparison.Ordinal))
{
ViewBag.State = state + " (valid)";
}
else
{
ViewBag.State = state + " (invalid)";
}
string code = Request.QueryString["code"] ?? "none";
string realmId = Request.QueryString["realmId"] ?? "none";
await GetAuthTokensAsync(code, realmId);
ViewBag.Error = Request.QueryString["error"] ?? "none";
return RedirectToAction("Tokens", "App");
}
/// <summary>
/// Exchange Auth code with Auth Access and Refresh tokens and add them to Claim list
/// </summary>
private async Task GetAuthTokensAsync(string code, string realmId)
{
if (realmId != null)
{
Session["realmId"] = realmId;
}
Request.GetOwinContext().Authentication.SignOut("TempState");
var tokenResponse = await AppController.auth2Client.GetBearerTokenAsync(code);
var claims = new List<Claim>();
if (Session["realmId"] != null)
{
claims.Add(new Claim("realmId", Session["realmId"].ToString()));
}
if (!string.IsNullOrWhiteSpace(tokenResponse.AccessToken))
{
claims.Add(new Claim("access_token", tokenResponse.AccessToken));
claims.Add(new Claim("access_token_expires_at", (DateTime.Now.AddSeconds(tokenResponse.AccessTokenExpiresIn)).ToString()));
}
if (!string.IsNullOrWhiteSpace(tokenResponse.RefreshToken))
{
claims.Add(new Claim("refresh_token", tokenResponse.RefreshToken));
claims.Add(new Claim("refresh_token_expires_at", (DateTime.Now.AddSeconds(tokenResponse.RefreshTokenExpiresIn)).ToString()));
}
var id = new ClaimsIdentity(claims, "Cookies");
Request.GetOwinContext().Authentication.SignIn(id);
}
}
注意:这是用户在身份验证完成后重定向到的控制器。
这是当我尝试调用未设置为对象实例的 api 对象引用时发生的错误。说明:执行当前 Web 请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。
异常详细信息:System.NullReferenceException:对象引用未设置为对象的实例。
源错误:
第 66 行://{ 第 67 行:var principal = User as ClaimsPrincipal; 第 68 行:
OAuth2RequestValidator oauthValidator = new OAuth2RequestValidator(principal.FindFirst("access_token").Value); 第 69 行:第 70 行://使用 Auth 令牌和 realmId 创建一个 ServiceContext
解决方案
刚刚遇到这个并找到了解决方案,也许可以节省其他人一些时间。
IntuitAPI 文档假设您正在使用 Cookie 身份验证
将此添加到 Startup.cs 然后试一试
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "TempState",
AuthenticationMode = AuthenticationMode.Passive
});
推荐阅读
- python - 在 Windows 10 中安装 mysqlclient 或/和 mysql-python 时出错
- haskell - 带有严格注释的`newtype`和`data`之间的区别
- python - 具有基于 Django Rest Framework 类的视图的 RestFul API 端点
- google-cloud-platform - 是否可以进行个人实例分割并使用从 Google API Vision 获得的网络在云外运行?
- mobile - Flutter 在小部件之间传递数据?
- architecture - DDD,你如何改变一个ValueObject?
- android - 如何使用 RecyclerView 和单个 ImageView 制作“完美”的 2 网格布局
- python - 如何在不恢复图形的情况下从 tensorflow 检查点提取权重和其他变量值?
- datepicker - 未捕获的错误:模块“AppModule”导入的意外指令“MatFormField”。请添加@NgModule 注释
- spring-boot - Spring Boot 无法从 cmd 找到可执行 jar 中的 ftl 文件