我遇到了一个PowerShell脚本的问题,我编写这个脚本来调用WCF Web服务上的方法。 WCF服务将复合DataContract作为其唯一的请求参数。我们最近修改了ServiceContract(通过添加两个新方法),但powershell脚本没有调用新方法。这是原始合同:
FOR /D %%a in (*) DO (
PUSHD "%%a"
FOR /D %%b in (*) DO RD /S /Q "%%b"
POPD
)
这是新合同:
[ServiceContract]
public interface IFileSystemService {
[OperationContract]
HashFileResponse HashFile(HashFileRequest req);
[OperationContract]
void GenerateFiles(GenerateFilesRequest req);
}
GenerateFiles方法是PowerShell脚本调用的方法。我们根本没有修改GenerateFilesRequest DataContract,它定义如下:
[ServiceContract]
public interface IFileSystemService {
[OperationContract]
HashFileResponse HashFile(HashFileRequest req);
[OperationContract]
void GenerateFiles(GenerateFilesRequest req);
[OperationContract]
ParseFilePathResponse ParseFilePath(ParseFilePathRequest req);
[OperationContract]
ArchiveParsedFileResponse ArchiveParsedFile(ArchiveParsedFileRequest req);
}
Baserequest目前是一个空类供将来使用(我们所有的请求数据合同都使用它):
[DataContract]
public class GenerateFilesRequest : BaseRequest {
[DataMember(IsRequired = true)]
public int Id { get; set; }
}
通过其他方式调用此方法可以始终如一地工作;在整个应用程序中定义了SoapUI,Fiddler和WCF合同。
在添加两个新方法之后,我们的集成测试失败了,因为powershell脚本无法在循环中一致地调用GenerateFiles方法(参见错误输出)。
当我最初编写这个脚本时,我遇到了类似的问题(虽然它要么一直破坏,要么一直有效)但我设法通过将-Namespace和-Class参数添加到New来获得服务调用。 -WebServiceProxy cmdlet。
上下文:我们在开发人员的计算机上运行powershell脚本,连接到IISExpress中托管的WCF服务。所有开发人员都遇到同样的问题。
这是我最近修改之前的原始脚本(首选)(这个工作正常,但现在大多数调用都失败了):
[DataContract]
public abstract class BaseRequest {
}
以下是脚本输出的摘录。如你所见,这是非常不一致的(标记为这样的行成功):
$sqlServer=$args[0]
function CallFSS($Id) {
$uri = "http://localhost:1234/FileSystemService.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri -Namespace fssNS -Class fssClass
$req = [fssNS.GenerateFilesRequest](New-Object fssNS.GenerateFilesRequest)
$req.Id= $Id
$response = $srv.GenerateFiles($req)
}
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=" + $sqlServer + ";Database=MyDatabase;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "select Id FROM MyTable WHERE Status = 2"
$SqlCmd.Connection = $SqlConnection
$sqlResult = $SqlCmd.ExecuteReader()
while ($sqlResult.Read()) {
$Id = $sqlResult.GetInt32(0)
Write-Host Generating files for Id $Id
CallFSS $Id
}
$SqlCmd.Dispose()
$SqlConnection.Dispose()
$SqlConnection.Close()
有时,大多数呼叫都会通过,只有奇数呼叫失败。
这是该脚本的另一个版本,它使用来自New-WebServiceProxy的自动生成的命名空间:
Generating files for Id 1
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Generating files for Id 2
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
**Generating files for Id 3**
Generating files for Id 4
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument Generating files for Id 8 Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
**Generating files for Id 9**
**Generating files for Id 10**
**Generating files for Id 11**
Generating files for Id 12
Cannot convert argument "req", with value: "fssNS.GenerateFilesRequest", for "GenerateFiles" to type "fssNS.GenerateFilesRequest": "Cannot convert the "fssNS.GenerateFilesRequest" value of type "fssNS.GenerateFilesRequest" to type "fssNS.GenerateFilesRequest"." At C:\SolutionPath\GENERATE_FILES.ps1:23 char:2
+ $response = $srv.GenerateFiles($req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
同样,结果是不一致的,虽然我现在得到的错误与自动生成的命名空间有关:
$sqlServer=$args[0]
function CallFSS($Id) {
$uri = "http://localhost:1234/FileSystemService.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri
$type = $srv.GetType().Namespace
$datatype = ($type + '.GenerateFilesRequest')
$req = New-Object($datatype)
$req.Id = $Id
$response = $srv.GenerateFiles($req)
}
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=" + $sqlServer + ";Database=MyDatabase;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "select Id FROM MyTable WHERE Status = 2"
$SqlCmd.Connection = $SqlConnection
$sqlResult = $SqlCmd.ExecuteReader()
while ($sqlResult.Read()) {
$Id = $sqlResult.GetInt32(0)
Write-Host Generating files for Id $Id
CallFSS $Id
}
$SqlCmd.Dispose()
$SqlConnection.Dispose()
$SqlConnection.Close()
等......执行每次都不同。
我非常希望这是我做错了/误解,因为我将完全放弃PowerShell。这可能是一个缓存问题吗?任何帮助将不胜感激。
答案 0 :(得分:1)
好的,我找到了一些东西:)
我在CallFSS函数中添加了GenerateFiles方法定义的输出:
$srv | gm -Name GenerateFiles | select -ExpandProperty Definition
Foreach成功请求,输出
void GenerateFiles(fssNS.GenerateFilesRequest req)
如果我遇到错误,定义会有所不同:
void GenerateFiles(fssNS.GenerateFilesRequest,oehlvn0y, Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null req)
因此,如果使用完全限定名称创建对象,则应该起作用:
function CallFSS($Id)
{
$uri = "http://localhost:11662/Service1.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri -Namespace fssNS -Class fssClass
# Get the definition of the GenerateFiles method
$definition = $srv | gm -Name GenerateFiles | select -ExpandProperty Definition
# Extract the full qualified type name of the first parameter
$paramType = [regex]::Match($definition, 'GenerateFiles\((.*)\s\w+').Groups[1].Value
$bar = new-object $paramType
$bar.Id = $Id
$response = $srv.GenerateFiles($bar)
}
注意:此解决方案仅适用于由于正则表达式而具有一个参数的方法。但是,这是我建议的实现:
function Invoke-FSS # Invoke is a valid Verb (see Get-Verb)
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)]
[int]$Id
)
Begin
{
$uri = "http://localhost:11662/Service1.svc?wsdl"
$srv = New-WebServiceProxy -Uri $uri -Namespace fssNS -Class fssClass
# Get the definition of the GenerateFiles method
$definition = $srv | gm -Name GenerateFiles | select -ExpandProperty Definition
# Extract the full qualified type name of the first parameter
$paramType = [regex]::Match($definition, 'GenerateFiles\((.*)\s\w+').Groups[1].Value
}
Process
{
$bar = new-object $paramType
$bar.Id = $Id
$response = $srv.GenerateFiles($bar)
}
End
{
$srv.Dispose()
}
}
在您的示例中,您将通过将id传递给Invoke-FFS
方法来调用该方法:
$ids = @()
while ($sqlResult.Read()) {
$ids += $sqlResult.GetInt32(0)
}
$ids | Invoke-FSS
Begin{}
块仅被调用一次(用于初始化代理),Process{}
块将被调用$ids
中的每个项目。最后,End{}
块在结束时被调用一次,以便优雅地处理代理。