Dynamics CRM - Downloading files from notes in C# results in corrupt files with FetchXML - dynamics-crm

I am using Dynamics CRM and am trying to download a file from the notes (annotation) entity. I am getting the Base64 String and converting to Byte[] like this:
Convert.FromBase64String((string)item.Attributes["documentbody"]);
But when I do so and try to open the file it is corrupt. Word Documents and PDFs refuse to open. Images however open partially. Ie. I get about 3/4 of the image but the rest of the image is solid grey.
I am guessing FetchXML is not returning the full string. Is there a way to to do this in FetchXML, overiding the limit? I have Googled but cannot see any mention of FetchXML limit?
There is a similar SO question here: FetchXml Query Returns Trimmed DocumentBody?
But I am not using "distinct" in my query.
Here is what I have so far:
<fetch>
<entity name="annotation" >
<attribute name="documentbody" />
<filter type="and" >
<condition attribute="objectid" operator="eq" value="{D4FFE0CD-CDFA-E711-80E4-005056BA77B6}" />
<condition attribute="isdocument" operator="eq" value="1" />
</filter>
<order attribute="modifiedon" descending="true" />
</entity>
</fetch>

You don't say how you are saving or opening the file, which I suspect is probably the issue.
Re: "I am guessing FetchXML is not returning the full string" - I don't think that is correct, I've not seen this happen.
This is a working example of saving a file to disk.
Exporting Annotation (Note) Attachment
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);
}
}
}

I believe your fetchXML query have the issue. I too faced the same issue but with images in SSRS reports. Images were not loaded properly/got corrupt.
I fixed the issue by updating the fetch XML query with distinct = false as in the below statement.
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false" >
.....
</fetch>

Related

Sitecore Custom Index - WARN Could not map index document (field: _uniqueid

I have created my custom Index in Sitecore with FlatDataCrawler.
The Index has been created and I can see my documents in Solr.
The problem is, whenever I'm trying to get those documents in my code I see exception like this:
Object reference not set to an instance of an object.
And in sitecore log file I see this WARN:
ManagedPoolThread #4 14:29:09 INFO Solr Query - ?q=*:*&rows=1000000&fq=_indexname:(products_index)&wt=xml
ManagedPoolThread #4 14:29:09 WARN Could not map index document (field: _uniqueid; Value: fae308d2-233f-4f7f-a4fd-9d880e42ff13) - Object reference not set to an instance of an object.
This is my Index config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:search="http://www.sitecore.net/xmlconfig/search/">
<sitecore role:require="Standalone or ContentManagement" search:require="solr">
<contentSearch>
<configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
<indexes hint="list:AddIndex">
<index id="products_index" type="Sitecore.ContentSearch.SolrProvider.SolrSearchIndex, Sitecore.ContentSearch.SolrProvider">
<param desc="name">$(id)</param>
<param desc="core">$(id)</param>
<param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
<configuration ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration">
<documentOptions type="Sitecore.ContentSearch.SolrProvider.SolrDocumentBuilderOptions, Sitecore.ContentSearch.SolrProvider">
<indexAllFields>false</indexAllFields>
</documentOptions>
</configuration>
<strategies hint="list:AddStrategy">
<strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/manual" />
</strategies>
<locations hint="list:AddCrawler">
<crawler type="Feature.ProductsIndex.Crawlers.CustomOrderCrawler, Feature.ProductsIndex" />
</locations>
</index>
</indexes>
</configuration>
</contentSearch>
</sitecore>
</configuration>
This is my code:
using (var searchContext = ContentSearchManager.GetIndex("products_index").CreateSearchContext())
{
int count = searchContext.GetQueryable<SearchResultItem>().Count(); //This works
var results = searchContext.GetQueryable<SearchResultItem>().ToList(); //Exception here!
}
See in your schema file , if you have
<uniqueKey>_uniqueid</uniqueKey>
<field name="_uniqueid" type="string" indexed="true" required="true" stored="true"/>
if not follow this link populate solr schema , and restart the solr service and then try to rebuild the index

How to use C# Web API in Dynamics 365

I am using online instance of Dynamics 365. I have created C# Web API to export data from activity entity. When I am running it from visual studio it's working fine.
Now I want to call it on button click in Dynamics 365. The requirement is that when user click on the button then the Web API should be call and data will be exported.
I don't have idea, how to get this task done. can anyone help me to solve this problem. kindly provide me steps to get this task.
Web API code is given below
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.ServiceModel;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;
using System.Windows.Forms;
namespace Experiments
{
class Program
{
private static OrganizationService _orgService;
static void Main(string[] args)
{
try
{
CrmConnection connection = CrmConnection.Parse(ConfigurationManager.ConnectionStrings["CrmOnline"].ConnectionString);
using (_orgService = new OrganizationService(connection))
{
var exportToExcelRequest = new OrganizationRequest("ExportToExcel");
exportToExcelRequest.Parameters = new ParameterCollection();
//Has to be a savedquery aka "System View" or userquery aka "Saved View"
//The view has to exist, otherwise will error out
exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("View", new EntityReference("savedquery", new Guid("{00000000-0000-0000-00AA-000010001902}"))));
exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("FetchXml", #"<?xml version='1.0'?>
<fetch distinct='false' mapping='logical' output-format='xml-platform' version='1.0'>
<entity name='activitypointer'>
<attribute name='subject'/>
<attribute name='ownerid'/>
<attribute name='prioritycode'/>
<attribute name='regardingobjectid'/>
<attribute name='activitytypecode'/>
<attribute name='statecode'/>
<attribute name='scheduledstart'/>
<attribute name='scheduledend'/>
<attribute name='activityid'/>
<attribute name='instancetypecode'/>
<attribute name='community'/>
<attribute name='senton'/>
<attribute name='statuscode'/>
<order descending='false' attribute='scheduledend'/>
<filter type='and'>
<condition attribute='actualdurationminutes' value='43800' operator='le'/>
</filter>
<link-entity name='systemuser' alias='activitypointerowningusersystemusersystemuserid' link-type='outer' visible='false' to='owninguser' from='systemuserid'>
<attribute name='internalemailaddress'/>
</link-entity>
<link-entity name='email' alias='email_engagement' link-type='outer' visible='false' to='activityid' from='activityid'><attribute name='isemailfollowed'/>
<attribute name='lastopenedtime'/>
<attribute name='delayedemailsendtime'/>
</link-entity>
</entity>
</fetch>"));
exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("LayoutXml", #"
<grid name='resultset' object='2' jump='fullname' select='1' icon='1' preview='1'>
<row name='result' id='activitypointerid'>
<cell name='activitytypecode' width='150' />
<cell name='statecode' width='112' />
<cell name='scheduledstart' width='110' />
<cell name='scheduledend' width='110' />
</row>
</grid>"));
//need these params to keep org service happy
exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("QueryApi", ""));
exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("QueryParameters",new InputArgumentCollection()));
var exportToExcelResponse = _orgService.Execute(exportToExcelRequest);
if (exportToExcelResponse.Results.Any())
{
File.WriteAllBytes("Activities.xlsx", exportToExcelResponse.Results["ExcelFile"] as byte[]);
}
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
string message = ex.Message;
throw;
}
}
}
}
Thanks.
I'd recommend you compile your C# code as an Action and include it as a step in a workflow. See here on how to invoke a custom action from a workflow.
I'd then recommend you install the Ribbon Workbench. This will let you customise your forms and navigations to add one or many buttons. You can use the workbench to customise these buttons, setting their commands to call your workflow which in turn calls your Action (your C# code).
Note there are several solutions to achieve what you're asking, I've just suggested one. Other solutions would likely include JavaScript and calling the Web API client-side.
Since you are using Dynamics 365 online, I will recommend you to create a Microsoft FLOW App with a CDS connector. Hope this helps.

EWS getting phone number from directory folder

I'm querying EWS with DistinguishedFolderId set to Directory. If I add
<t:FieldURI FieldURI="persona:PhoneNumber" />
to the field URIs I don't get the phone number returned. Also if I try to expand the BaseShape to AllProperties I get a failure.
<soap:Body>
<m:FindItem Traversal="Shallow">
<m:ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
<t:AdditionalProperties>
<t:FieldURI FieldURI="persona:DisplayName" />
</t:AdditionalProperties>
</m:ItemShape>
<m:IndexedPageItemView MaxEntriesReturned="100" Offset="0" BasePoint="Beginning" />
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="directory" />
</m:ParentFolderIds>
</m:FindItem>
</soap:Body>
What I'm trying to do is construct a query which will return me the person (not the contact, I need to look into the directory not the contacts) details with the phone number from the tenant.
Ok - found the answer to this one. FindPeople and FindItems aren't going to return the phone number by default, that's some kind of extension.
See here and here where it was partially answered on msdn forums. The solution proposal is to use the GetPersona method and query each PersonId individually.

Orchard CMS Data Import

I am attempting to import data into Orchard CMS. I have a custom type, made up of parts and fields, and I am using the ImportExport module. I have exported some data from Orchard to ensure the XML schema is correct, but when importing, the only field that seems to be populating is the TitlePart Title. I have randomly generated a GUID for the identifier of each record. Orchard 1.4, ImportExport 1.4.
Example of one item of data:
<Orchard>
<Recipe>
<Name>Data Import</Name>
<Author>myaccount</Author>
</Recipe>
<Data>
<OurPropertiesDivision Id="/Identifier=94eff3237c714f98b021905c33d25ea9" Status="Published">
<LinkField.Link Text="This is a link" Url="http://stackoverflow.com" />
<MediaPickerField.ImageOne Url="~/test.jpg" Width="100" Height="100" />
<MediaPickerField.ImageTwo Url="~/test2.jpg" Width="100" Height="100" />
<MediaPickerField.ImageThree Url="~/test3.jpg" Width="100" Height="100" />
<TitlePart Title="Test Title" />
<CommonPart Owner="/User.UserName=myaccount" CreatedUtc="2012-04-04T23:03:39Z" PublishedUtc="2012-04-04T23:03:39Z" ModifiedUtc="2012-04-04T23:03:39Z" />
<IdentityPart Identifier="94eff3237c714f98b021905c33d25ea9" />
</OurPropertiesDivision>
</Data>
</Orchard>
This results in the following when looking at the imported entry:
Content list:
Edit screen:
The only field that is making it through the import is the TitlePart. How can I make this work in a way that I can bulk insert any type of field or part with data? I would also like to capture the Container for the Containable part.
EDIT: Adding content type metadata
<?xml version="1.0"?>
<!--Exported from Orchard-->
-<Orchard>
-<Recipe>
<Name>Generated by Orchard.ImportExport</Name>
<Author>myaccount</Author>
</Recipe> -<Metadata>
-<Types>
-<OurPropertiesDivision DisplayName="Our Properties - Division" ContentTypeSettings.Draftable="True" ContentTypeSettings.Creatable="True">
<CommonPart DateEditorSettings.ShowDateEditor="False" OwnerEditorSettings.ShowOwnerEditor="False"/>
<TitlePart/>
<OurPropertiesDivision/>
<ContainablePart/>
<IdentityPart/>
</OurPropertiesDivision>
</Types> -<Parts>
<CommonPart ContentPartSettings.Attachable="True"/> <TitlePart ContentPartSettings.Attachable="True"/> -<OurPropertiesDivision ContentPartSettings.Attachable="True">
<ImageOne.MediaPickerField DisplayName="Image One" MediaPickerFieldSettings.Required="False" HtmlFieldSettings.FlavorDefault="html"/>
<ImageTwo.MediaPickerField DisplayName="Image Two" MediaPickerFieldSettings.Required="False" HtmlFieldSettings.FlavorDefault="html"/>
<ImageThree.MediaPickerField DisplayName="Image Three" MediaPickerFieldSettings.Required="False" HtmlFieldSettings.FlavorDefault="html"/>
<Content.HtmlField DisplayName="Content" HtmlFieldSettings.FlavorDefault="html"/>
<Link.LinkField DisplayName="Link" HtmlFieldSettings.FlavorDefault="html" LinkFieldSettings.LinkTextMode="Required" LinkFieldSettings.TargetMode="NewWindow" LinkFieldSettings.Required="True"/>
</OurPropertiesDivision> <ContainablePart ContentPartSettings.Attachable="True"/> <IdentityPart ContentPartSettings.Attachable="True"/>
</Parts>
</Metadata>
</Orchard>
I ended up analyzing the database inserts generated by the admin, and manually importing the data in SQL.

Missing schema in DBML if using LINQ to SP and Sp returning multiple record sets

while making of POC of LINQ to SQL and entities, i faced a problem stuck in a frozen dead end.
Problem is , am using LINQ to SP and every things was working fine and i made cool methods of editing, adding and deleting. Then some thing click in my mine that "what if i just return two record set from SP". i made a SP and returned two record set from it
SP look like this [Demo]
Create PROCEDURE [dbo].GetUserData
#UserId Bigint
AS
BEGIN
SET NOCOUNT ON;
-- Getting User
select * from [User] where id=#UserId
-- Getting User's role
select * from [Role] where userId=#UserId
end
then i droped that SP in my DBML (Linq to SQL classes) then here i noticed that only schema of one record set was created like this
<?xml version="1.0" encoding="utf-8"?>
<Database Name="MyInventory" Class="MyDBMLDataContext" xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
<Connection Mode="AppSettings" ConnectionString="Data Source=MyDatabaseServer\;Initial Catalog=MyInventory;Integrated Security=True" SettingsObjectName="ConsoleApplication16.Properties.Settings" SettingsPropertyName="MyInventoryConnectionString" Provider="System.Data.SqlClient" />
<Function Name="dbo.GetUserData" Method="GetUserData">
<Parameter Name="UserId" Parameter="userId" Type="System.Int64" DbType="BigInt" />
<ElementType Name="GetUserDataResult">
<Column Name="Id" Type="System.Int64" DbType="BigInt NOT NULL" CanBeNull="false" />
<Column Name="Name" Type="System.String" DbType="VarChar(50) NOT NULL" CanBeNull="false" />
<Column Name="Email" Type="System.String" DbType="NVarChar(50)" CanBeNull="true" />
<Column Name="IsDeleted" Type="System.Boolean" DbType="Bit NOT NULL" CanBeNull="false" />
<Column Name="HomePage" Type="System.String" DbType="VarChar(100)" CanBeNull="true" />
</ElementType>
</Function>
</Database>
i can clearly see that only one record set is created of Users records and it is missing Role schema :(.
Can any body tell me what and why is that so?
Thanks
Lura
I have had to deal with something similar in getting multiple data sets from a data base for a website. What we did was create an DatabaseExtensions.cs file to add the queries with multiple data sets.
So in the extensions file we would have something like this
public partial class DataBaseDataContext
{
[ResultType(typeof(FirstResult))]
[ResultType(typeof(SecondResult))]
[Function(Name = "dbo.StoredProc")]
public IMultipleResults StoredProc([global::System.Data.Linq.Mapping.ParameterAttribute(DbType = "Int")] System.Nullable<System.Int> ID)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), ID);
return ((IMultipleResults)(result.ReturnValue));
}
}
public class FirstResult;
public class SecondResult;
Note: I changed some of the names of things in this code to make it easier to read, so it may not work as is.
FirstResult and SecondResult are the result type classes. I would usually copy them from the dbml's accompanying .cs file then rename it. I didn't include their code here because it can be rather long.
DataBaseDataContext dataCon = new DataBaseDataContext();
var results = dataCon.StoredProc(id);
var firstSet = results.GetResult<FirstResult>();
var secondSet = results.GetResult<SecondResult>();
//process data
It is important to get your results out in the same order they come out in your stored procedure. After you have gotten your results out, you can use LINQ or whatever to work with them.
My finding is that if you add a result set to your dbml manually you get the results that you want but LinqToSql doesn't offer you a simple way to have access to them
Here is a path to your results
((System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReaderSession
<System.Data.SqlClient.SqlDataReader>)
(((System.Data.Linq.SqlClient.SqlProvider.ExecuteResult)(result)).session)).buffer
you here have access to your result by index buffer[0] will return the results of your first select statement and buffer[1] returns the result of second select.
probably you can cast this two IEnumerables to typed IEnumerable<GetAllResult> and IEnumerable<GetAllResult1> although I didn't test that.
I build this sample dbml
<Function Name="dbo.GetAll" Method="GetAll">
<ElementType Name="GetAllResult">
<Column Name="ID" Type="System.Int32" DbType="Int" CanBeNull="true" />
<Column Name="Tagname" Type="System.String" DbType="NChar(10)" CanBeNull="true" />
</ElementType>
<ElementType Name="GetAllResult1">
<Column Name="Id" Type="System.Int32" DbType="Int" CanBeNull="true" />
<Column Name="TagId" Type="System.Int32" DbType="Int" CanBeNull="true" />
<Column Name="Name1" Type="System.String" DbType="NChar(10)" CanBeNull="true" />
</ElementType>
</Function>
and the generated cs file would be like this
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.GetAll")]
[global::System.Data.Linq.Mapping.ResultTypeAttribute(typeof(GetAllResult))]
[global::System.Data.Linq.Mapping.ResultTypeAttribute(typeof(GetAllResult1))]
public IMultipleResults GetAll()
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())));
return ((IMultipleResults)(result.ReturnValue));
}
Have you looked code generated for your model? Two resultsets will be here. Mapping can lie.
Ramesh

Resources