从 Note 实体下载附件并保存到 Microsoft Dynamics CRM 中的本地计算机时出现插件路径错误
Getting Plug-In Path error while Downloading attachments from Note entity and saving into local machine in Microsoft Dynamics CRM
业务流程错误
System.ArgumentException: Illegal characters in path. at
System.IO.Path.GetFileName(String path) at
System.IO.File.InternalWriteAllBytes(String path, Byte[] bytes,
Boolean checkHost)at
RetrieveAttachments.RetrieveClass.Execute(IServiceProvider
serviceProvider)
代码如下:
QueryExpression notes = new QueryExpression { EntityName = "annotation", ColumnSet = new ColumnSet("filename", "subject", "annotationid", "documentbody","mimetype") };
notes.Criteria.AddCondition("annotationid", ConditionOperator.Equal, annotationid);
EntityCollection NotesRetrieve = service.RetrieveMultiple(notes);
if (NotesRetrieve != null && NotesRetrieve.Entities.Count > 0)
{
foreach (var note in NotesRetrieve.Entities)
{
string fileName = note.GetAttributeValue<string>("filename");
//string fileType = note.GetAttributeValue<string>("mimetype");
FileIOPermission f = new FileIOPermission(FileIOPermissionAccess.Write, "D:\note");
string fileLocation = f+ fileName;
byte[] fileContent = Convert.FromBase64String(NotesRetrieve.Entities[0].Attributes["documentbody"].ToString());
System.IO.File.WriteAllBytes(fileLocation, fileContent);
}
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.ToString());
}
这条线是你的罪魁祸首:
string fileLocation = f+ fileName;
此行将创建一个无效的文件名,因为 FileIOPermission.ToString()
returns 一个 XML 片段。
这里是修复该问题的示例,清除文件名中的非法字符,并使用 Path.Combine
构建有效的文件路径。
string fileName = note.GetAttributeValue<string>("filename");
string cleanFileName = string.Empty;
foreach (var chr in fileName.ToCharArray().ToList())
{
if (!Path.GetInvalidFileNameChars().Contains(chr)) cleanFileName = cleanFileName + chr;
}
FileIOPermission f = new FileIOPermission(FileIOPermissionAccess.Write, @"D:\note");
string fileLocation = Path.Combine(@"D:\note", cleanFileName);
byte[] fileContent = Convert.FromBase64String(NotesRetrieve.Entities[0].Attributes["documentbody"].ToString());
System.IO.File.WriteAllBytes(fileLocation, fileContent);
D:\note is a path of my machine where the file is downloaded.
如果以上说明您正在尝试使用 CRM 插件将数据写入本地计算机(而不是 CRM 服务器),那么这将永远行不通。
该插件在 CRM 服务器上运行,因此它无法访问您的客户端计算机。例如。当插件运行时,它会在 CRM 服务器上寻找 D:\note
- 而不是在您的个人计算机上。
如果要将文件下载到本地计算机,最好创建一个在本地计算机上运行的控制台应用程序。
无论如何都有附件下载的例子here。 filePath
在你的情况下将是 D:\note
(虽然这在插件中仍然不起作用)。
public void ExportDocuments(IOrganizationService service, String filePath)
{
String fetch = @"<fetch mapping='logical' count='100' version='1.0'>
<entity name='annotation'>
<attribute name='filename' />
<attribute name='documentbody' />
<attribute name='mimetype' />
</entity>
</fetch>";
foreach (Entity e in service.RetrieveMultiple(new FetchExpression(fetch)))
{
if (!String.IsNullOrWhiteSpace(e.Attributes["documentbody"].ToString()))
{
byte[] data = Convert.FromBase64String(e.Attributes["documentbody"].ToString());
File.WriteAllBytes(filePath + e.Attributes["filename"].ToString(), data);
}
}
}
CRM Online 仅支持沙盒模式,这意味着它隔离了代码,您无法在沙盒模式下访问外部环境,在您的情况下是您的本地计算机驱动器。
为了实现您的目标,您可以创建一个控制台应用程序,如 James Wood 所说,它将文件写入您的本地计算机。
桑托什,
您可以使用以下代码从在线 Dynamics CRM 中的备注实体下载附件。
.cs 文件代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int choice;
CrmServiceClient crmConn = new CrmServiceClient(ConfigurationManager.ConnectionStrings["CRM"].ConnectionString);
IOrganizationService crmService = crmConn.OrganizationServiceProxy;
QueryExpression w_query = new QueryExpression { EntityName = "annotation", ColumnSet = new ColumnSet("filename","documentbody") };
EntityCollection w_account = crmService.RetrieveMultiple(w_query);
string name = "";
foreach (var count in w_account.Entities)
{
name = count.GetAttributeValue<string>("filename");
string doc_content = count.GetAttributeValue<string>("documentbody");
System.IO.FileStream wFile;
byte[] byteData = null;
if (name != null)
{
byte[] doc = Convert.FromBase64String(count.GetAttributeValue<string>("documentbody"));
byteData = doc;
wFile = new FileStream("D:\attachments\" + name, FileMode.Append);
wFile.Write(byteData, 0, byteData.Length);
wFile.Close();
}
}
Console.WriteLine("Please find all attachments in your local D: drive");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}
.config 文件的代码:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="CRM" connectionString="AuthType=Office365;Url=https://your_organization_url; Username=your_user_name; Password=Your_password" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.22.0.0" newVersion="2.22.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.22.0.0" newVersion="2.22.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
您只需编辑 .config 文件代码,这应该适合您。
注意:您必须创建 C# 控制台应用程序并从 Nuget 添加所需的程序集。
业务流程错误
System.ArgumentException: Illegal characters in path. at System.IO.Path.GetFileName(String path) at System.IO.File.InternalWriteAllBytes(String path, Byte[] bytes, Boolean checkHost)at RetrieveAttachments.RetrieveClass.Execute(IServiceProvider serviceProvider)
代码如下:
QueryExpression notes = new QueryExpression { EntityName = "annotation", ColumnSet = new ColumnSet("filename", "subject", "annotationid", "documentbody","mimetype") };
notes.Criteria.AddCondition("annotationid", ConditionOperator.Equal, annotationid);
EntityCollection NotesRetrieve = service.RetrieveMultiple(notes);
if (NotesRetrieve != null && NotesRetrieve.Entities.Count > 0)
{
foreach (var note in NotesRetrieve.Entities)
{
string fileName = note.GetAttributeValue<string>("filename");
//string fileType = note.GetAttributeValue<string>("mimetype");
FileIOPermission f = new FileIOPermission(FileIOPermissionAccess.Write, "D:\note");
string fileLocation = f+ fileName;
byte[] fileContent = Convert.FromBase64String(NotesRetrieve.Entities[0].Attributes["documentbody"].ToString());
System.IO.File.WriteAllBytes(fileLocation, fileContent);
}
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.ToString());
}
这条线是你的罪魁祸首:
string fileLocation = f+ fileName;
此行将创建一个无效的文件名,因为 FileIOPermission.ToString()
returns 一个 XML 片段。
这里是修复该问题的示例,清除文件名中的非法字符,并使用 Path.Combine
构建有效的文件路径。
string fileName = note.GetAttributeValue<string>("filename");
string cleanFileName = string.Empty;
foreach (var chr in fileName.ToCharArray().ToList())
{
if (!Path.GetInvalidFileNameChars().Contains(chr)) cleanFileName = cleanFileName + chr;
}
FileIOPermission f = new FileIOPermission(FileIOPermissionAccess.Write, @"D:\note");
string fileLocation = Path.Combine(@"D:\note", cleanFileName);
byte[] fileContent = Convert.FromBase64String(NotesRetrieve.Entities[0].Attributes["documentbody"].ToString());
System.IO.File.WriteAllBytes(fileLocation, fileContent);
D:\note is a path of my machine where the file is downloaded.
如果以上说明您正在尝试使用 CRM 插件将数据写入本地计算机(而不是 CRM 服务器),那么这将永远行不通。
该插件在 CRM 服务器上运行,因此它无法访问您的客户端计算机。例如。当插件运行时,它会在 CRM 服务器上寻找 D:\note
- 而不是在您的个人计算机上。
如果要将文件下载到本地计算机,最好创建一个在本地计算机上运行的控制台应用程序。
无论如何都有附件下载的例子here。 filePath
在你的情况下将是 D:\note
(虽然这在插件中仍然不起作用)。
public void ExportDocuments(IOrganizationService service, String filePath)
{
String fetch = @"<fetch mapping='logical' count='100' version='1.0'>
<entity name='annotation'>
<attribute name='filename' />
<attribute name='documentbody' />
<attribute name='mimetype' />
</entity>
</fetch>";
foreach (Entity e in service.RetrieveMultiple(new FetchExpression(fetch)))
{
if (!String.IsNullOrWhiteSpace(e.Attributes["documentbody"].ToString()))
{
byte[] data = Convert.FromBase64String(e.Attributes["documentbody"].ToString());
File.WriteAllBytes(filePath + e.Attributes["filename"].ToString(), data);
}
}
}
CRM Online 仅支持沙盒模式,这意味着它隔离了代码,您无法在沙盒模式下访问外部环境,在您的情况下是您的本地计算机驱动器。
为了实现您的目标,您可以创建一个控制台应用程序,如 James Wood 所说,它将文件写入您的本地计算机。
桑托什,
您可以使用以下代码从在线 Dynamics CRM 中的备注实体下载附件。
.cs 文件代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int choice;
CrmServiceClient crmConn = new CrmServiceClient(ConfigurationManager.ConnectionStrings["CRM"].ConnectionString);
IOrganizationService crmService = crmConn.OrganizationServiceProxy;
QueryExpression w_query = new QueryExpression { EntityName = "annotation", ColumnSet = new ColumnSet("filename","documentbody") };
EntityCollection w_account = crmService.RetrieveMultiple(w_query);
string name = "";
foreach (var count in w_account.Entities)
{
name = count.GetAttributeValue<string>("filename");
string doc_content = count.GetAttributeValue<string>("documentbody");
System.IO.FileStream wFile;
byte[] byteData = null;
if (name != null)
{
byte[] doc = Convert.FromBase64String(count.GetAttributeValue<string>("documentbody"));
byteData = doc;
wFile = new FileStream("D:\attachments\" + name, FileMode.Append);
wFile.Write(byteData, 0, byteData.Length);
wFile.Close();
}
}
Console.WriteLine("Please find all attachments in your local D: drive");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}
.config 文件的代码:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="CRM" connectionString="AuthType=Office365;Url=https://your_organization_url; Username=your_user_name; Password=Your_password" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.22.0.0" newVersion="2.22.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.22.0.0" newVersion="2.22.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
您只需编辑 .config 文件代码,这应该适合您。
注意:您必须创建 C# 控制台应用程序并从 Nuget 添加所需的程序集。