【问题标题】:Powershell not invoking method in a c# objectPowershell不在c#对象中调用方法
【发布时间】:2020-10-10 04:34:22
【问题描述】:

我有一堆由我编写的 C# 库,应该被 PowerShell 脚本用来在我们的环境中执行各种 devops 任务。 最奇怪的事情正在发生,我认为这与我的 PowerShell 脚本中库的外部加载有关。

工作示例

首先,我将演示通用代码和一个这样的类的工作原理,以便您了解我是如何使用它的: 我们首先为我的 API 加载外部库

$binpath = "$PSScriptRoot\bin"
#Reads credentials
Add-Type -Path "$binpath\CredentialHandling.dll"
#Is used for logging
Add-Type -Path "$binpath\OperationLogging.dll"
#Is used to handle the different dev environments (we have a lot of them!)
Add-Type -Path "$binpath\IdmEnvironmentHandling.dll"
#Is used to perform operations in LDAP
Add-Type -Path "$binpath\IdmLdapInteractions.dll"
#Is used to perform operations with a specific REST API service
#The base library that contains general methods and binds it all together
Add-Type -Path "$binpath\IdmApi.dll"

我设置了应该在 C# 代码中调用构造函数的对象,然后继续在其中一个连接器上执行方法

#The IdmApiOperator contains multiple connectors to different platforms to perform unified tasks
$idm = [IdmApi.IdmApiOperator]::new($environment)
$searchbase = 'ou=OrganizationalUnit,o=SYSTEM'
$ldapFilter = '(cn=CommonNameExample)'
#This will return some sort of ldap search response, which works
$search = $idm.LdapOperator.Search($searchbase, ldapFilter)

此代码上下文中的 Ldap 运算符使用标准 .NET 库 System.DirectoryServices.Protocols,它的工作方式非常棒,所有实际代码都在 C# 和 PowerShell 中运行。

IdmApiConnector 的成员(运算符的基类,有点像接口)

行不通的例子

我们首先为我的 API 加载外部库,这次包括一个用于 REST API 的库,对 RestOperator 类的调用将失败,我不明白为什么

$binpath = "$PSScriptRoot\bin"
#Reads credentials
Add-Type -Path "$binpath\CredentialHandling.dll"
#Is used for logging
Add-Type -Path "$binpath\OperationLogging.dll"
#Is used to handle the different dev environments (we have a lot of them!)
Add-Type -Path "$binpath\IdmEnvironmentHandling.dll"
#Is used to perform operations in LDAP
Add-Type -Path "$binpath\IdmLdapInteractions.dll"
#Is used to perform operations with a specific REST API service
Add-Type -Path "$binpath\IdmRestInteractions.dll"
#Used by IdmRestInteractions, put in here just to be safe
Add-Type -Path "$binpath\RestSharp.dll"
#The base library that contains general methods and binds it all together
Add-Type -Path "$binpath\IdmApi.dll"

$idm = [IdmApi.IdmApiOperator]::new($environment)
#Purely a test, this method will return an Oauth token for the specified connection, this method is a derivative of the actual method that will set a token property in the base class.
$token = $idm.RestOperator.GetToken()
#Will return null, not even an error is thrown

GetToken() 方法的代码,它返回一个 IdmToken,定义在 IdmRestInteractions.Objects 下的同一命名空间中

public IdmToken GetToken()
        {
            string path = MethodPaths["OAuthUri"];
            RestRequest request = new RestRequest()
            {
                Method = Method.POST,
                Resource = path,
            };
            string authstring = GetOAuthString();
            request.AddHeader("Authorization", authstring);
            string body = ""//here it creates the body, removed in this version
            request.AddParameter("application/x-www-form-urlencoded", body, ParameterType.RequestBody);
            IRestResponse response = Client.Post(request); //Client here being an IRestClient object from the library RestSharp
            return JsonConvert.DeserializeObject<IdmToken>(response.Content);
        }

查看tomcat主机,该方法似乎没有通过什么的,因为服务器没有收到任何请求。 将方法的输出改成乱码会使其返回乱码,所以并不是没有触发该方法。 我还尝试将 Newtonsoft.Json 添加到我的 PowerShell 代码中,但这也没有改变任何东西。 当然,当我稍后在我的程序中使用该令牌时,它会给出一个 nullref 异常......

总结

  • 我使用自己在 PowerShell 脚本中以 .dll 格式编写的库。
  • 一个有效,一个无效,问题不在于库的使用或实现
  • Rest Api 连接器使用外部库 RestSharp(这可能是原因?)
  • 方法被触发,但不向服务执行 API 请求
  • 最重要的是,代码确实可以在 C# 中本地运行,这不像我没有经过身份验证

【问题讨论】:

  • 缺乏服务器端活动本身并不能证明没有调用客户端方法 - 如果其余客户端静默失败请求并且response.Content 为空,JsonConvert.DeserializeObject&lt;IdmToken&gt;() 将返回 @ 987654332@.
  • 只是一个虚拟的猜测,你说你的 dll 使用 restsharp.dll 但在我的理解中,没有魔法可以告诉你的 dll 在哪里寻找 restsharp.dll 并简单地加载它不会做我认为的诀窍。在 PowerShell 的末尾不执行链接器的工作,它只是加载 dll,以便您可以访问那里的代码。

标签: c# powershell restsharp


【解决方案1】:

我快速浏览了docsthis 的答案。客户端默认不会抛出异常。 Content 将只是空的,您的方法将静默失败并返回 null。可能的解决方案包括检查ErrorException 属性或设置ThrowOnAnyError

# option 1
Client.ThrowOnAnyError = true;

# option 2
if (response.ErrorException != null)
{
    throw new Exception("Request failed.", response.ErrorException);
} 

【讨论】:

  • 我本来打算明天试试这个,如果代码在 c# 中运行,在 powershell 中调试功能有点困难。我将测试方法的输出更改为 IRestResponse 类,并检查那里的内容。
  • @ThomErnst 为了调试,你可以在纯 PowerShell 中重写这个函数。
  • @marsze RestSharp 大量使用扩展方法,我不建议在 PowerShell 中重写它
  • 好吧,事实证明它确实没有抛出任何错误,我让该方法将 IRestResponse 对象返回给 powershell,我立即看到它包含一个 SSL 上下文错误,我修复了这个问题。我确实对类中的所有方法都有异常处理,除了生成令牌的方法,我假设如果它尝试生成令牌并失败,它会自行抛出异常,似乎我错了。
猜你喜欢
  • 2016-06-19
  • 1970-01-01
  • 2023-03-03
  • 2011-01-28
  • 1970-01-01
  • 2016-11-04
  • 1970-01-01
  • 1970-01-01
  • 2012-06-10
相关资源
最近更新 更多