Sharepoint 2010 | Infopath Listform von TEST auf PROD deployen

Hallo Leute,

mittlerweile habe ich auch mit den ersten Infopath-Sharepoint Formularen zu tun.

Vorweg: Geht man einfach im Sharepoint unter Listentools -> Liste -> Formular anpassen, so hat man einige Einschneidungen, z.B.:
* Entwicklertools im InfoPath stehen nicht zur Verfügung
* Deployment gestaltet sich schwierig

Ich möchte hier insbesondere auf den zweiten Punkt eingehen:
Denn Wenn man auf diese Art das Formular anpasst, kann man im InfoPath selbst die primäre Datenquelle nicht mehr verändern, ein Deployment für eine andere Liste bzw. auf einem anderen Server ist also nicht möglich …

2013-05-10 09_59_29-Datenverbindungen

Nach ein wenig Recherche habe ich „herausgefunden“, dass sich hinter der Extension „xsn“ eigentlich nur ein CAB-File versteckt, welches man einfach (umbenennen und) extrahieren kann. Man findet dann eine Datei Namens „manifest.xsn“, welche man am besten im Notepad (oder einem anderen Text-Editor) öffnet.

Nun sucht man nach „ListId“ und findet:
sharePointListID="{32D6310F-88CF-4C32-BAFC-B974A717D7BD}" contentTypeID="0x0100ABD98D05E8DE754086E57FD6330C5060"

Diese beiden Werte muss man durch jene des Zielsystems ersetzen.

Anschliessend sucht man nach „baseUrl“ und findet:

Auch hier ersetzt man die URL durch die neue/PROD-Sharepoint URL.

Wichtig: Die Liste muss bereits am Zielsystem existieren. 100%ig ident muss sie nicht sein – aber dazu später.

Nun muss man die Dateien wieder in ein XSN-Dokument verpacken. Ich habe hierfür folgendes gefunden:


;************************************************************

; MSDN Sample Source Code MakeCAB Directive file example

;************************************************************

.OPTION EXPLICIT

;*****************************************************************

; change the value of the caninet name for example myInfoPath.xsn

;******************************************************************

.Set CabinetNameTemplate=20131005_test.XSN

;**********************************************************************************************

; change the value of the Disk Directory Template value to the directory you want to store the xsn file into,,

;**********************************************************************************************

.set DiskDirectoryTemplate="C:\Users\user\Desktop"

.Set Cabinet=on

.Set Compress=on

;*******************************************************

; Just List All the files to be added in the xsn file

;*******************************************************

"C:\Users\user\Desktop\temp\Choices Data Connection39.xsd"
"C:\Users\user\Desktop\temp\choices.xml"
"C:\Users\user\Desktop\temp\Ergnzungen-E.xsl"
"C:\Users\user\Desktop\temp\ErgnzungenIT.xsl"
"C:\Users\user\Desktop\temp\ITPSE.xsl"
"C:\Users\user\Desktop\temp\manifest.xsf"
"C:\Users\user\Desktop\temp\Planung.xsl"
"C:\Users\user\Desktop\temp\sampledata.xml"
"C:\Users\user\Desktop\temp\schema.xsd"
"C:\Users\user\Desktop\temp\schema1.xsd"
"C:\Users\user\Desktop\temp\schema2.xsd"
"C:\Users\user\Desktop\temp\schema3.xsd"
"C:\Users\user\Desktop\temp\schema4.xsd"
"C:\Users\user\Desktop\temp\template.xml"
"C:\Users\user\Desktop\temp\upgrade.xsl"
"C:\Users\user\Desktop\temp\view1.xsl"
"C:\Users\user\Desktop\temp\Vorhaben.xsl"
"C:\Users\user\Desktop\temp\WEintern.xsl"

;*********************

; End of the File

;*********************

Wichtig ist, dass alle Dateien in der Auflistung am Ende vorkommen. Das fertige XSN-File muss dann wieder in der Entwurfsansicht geöffnet werden.
InfoPath wirft dann sofort folgende Meldung auf:

2013-05-10 10_07_05-(Entwurf) Formular1 [Schreibgeschützt] - Microsoft InfoPath

Ich habe mit [JA] geantwortet, was die Felder korrekt aktualisiert hat. Was bei [Nein] genau passiert, kann ich nicht sagen.
Anschließend kann man die primäre Datenquelle überprüfen und wird die neue URL sehen. Auch das Deployment funktioniert dann gegen das Zielsystem.

Cheers,
Christian

Advertisements
Veröffentlicht unter InfoPath 2010, Sharepoint, Sharepoint 2010 | Kommentar hinterlassen

CRM 2011 – Doubleclick im Subgrid deaktivieren/verhinden

Nach langer Zeit mal wieder was zum Thema CRM:

Nachdem wir in einem Projekt leider sehr große Hierarchien haben und die Subgrids bekanntermassen ja nur zwei Ebenen anzeigen, haben wir uns eine Art Schattenentität als Lösung einfallen lassen. Diese fungiert quasi als Linker zu den einzelnen Abhängigkeiten. Wie auch immer. Wir zeigen nun auf ein paar Formularen eine Art „Überblick“ an, die Daten in den Subgrids sind vom Typ „cust_linkentity“.

Das hat die negative Folgeerscheinung, dass bei Doppelklick das Standard-Formular der Entität „cust_linkentity“ geöffnet wird, obwohl diese Entität rein aus funktionellen Gründen existiert und für den Kunden eigentlich unsichtbar sein sollte.

Leider gibt es keinen von Microsoft unterstützten Weg, das zu verhindern. Meine Recherche hat mich zur Datei „AppGrid_DefaultData.htc“ gebracht, welche unter anderem die Funktion „handleDblClick()“ enthält.

ACHTUNG: Die nachfolgende Lösung ist von Microsoft explizit nicht supported!! Bitte nur machen, wenn Ihr euch über die Folgen im Klaren seid!

Original

function handleDblClick()
                                           {
                                               o = getSrcRow();
                                               if (!IsNull(o))
                                                   if ((event.ctrlKey || event.srcElement.tagName == "INPUT" && event.srcElement.type == "checkbox") && o.selected)
                                                       unselectRow(o, true, true);
                                                   else
                                                       handleSelectRow(o);

                                               var oSelectedRecords = getSelectedRecords();

                                               if (oSelectedRecords.length == 0)
                                                   return;

                                               var oSelRec = oSelectedRecords[0], oTr = oSelRec[3];

                                               openRecord(oTr);
                                               
                                           }

Wie Ihr seht, wird als Letztes mit „openRecord“ das Formular der Entität geöffnet.

Angepasst

function handleDblClick()
                                           {
                                               o = getSrcRow();
                                               if (!IsNull(o))
                                                   if ((event.ctrlKey || event.srcElement.tagName == "INPUT" && event.srcElement.type == "checkbox") && o.selected)
                                                       unselectRow(o, true, true);
                                                   else
                                                       handleSelectRow(o);

                                               var oSelectedRecords = getSelectedRecords();

                                               if (oSelectedRecords.length == 0)
                                                   return;

                                               var oSelRec = oSelectedRecords[0], oTr = oSelRec[3];

                                               var typename = o.getAttribute("otypename");
                                               if (typename != "cust_linkentity") {

                                                   openRecord(oTr);
                                               }
                                           }

Ich habe hier eine einfache Condition eingebaut, die das Formular nur öffnet, wenn es sich nicht um diesen einen bestimmten Typ handelt.

Cheers,
Chris

Veröffentlicht unter Javascript | Verschlagwortet mit , , , | Kommentar hinterlassen

Scrolling in Subgrid

Sind heute vor folgende Herausforderung gestellt worden:

Ein Subgrid zeigt auf einer Seite 5 Records. Der Kunde möchte jedoch 10 Records auswählen (verteilt auf mehrere Seiten). Das Grid verliert jedoch nach dem Umblättern die Auswahl von der vorhergehenden Seite, was zu fachlichen Problemen führen könnte.

Sind dabei auf MSCRM-Kings-Blog gestossen. Der Kollege stellt einfach ein, dass 250 Records auf einer Seite dargestellt werden sollen und quätscht das Grid dann einfach mittels CSS auf die Höhe von 5 bzw. X Records zusammen.

Funktioniert in unserem Fall super. Hat jedoch die Limitierung, dass der Kunde auf diesem Wege maximal 250 Records auswählen kann (Limitierung seitens Microsoft für die Darstellung auf einer Seite), bevor das Problem von vorne los geht. Wird in unserem Fall sicher nicht passieren.

Hier der Link zum Blog: http://www.mscrmking.com/2011/07/crm-2011-adding-scrollbars-to-a-sub-grid/#comment-213

Und nun der Code:

//Warning: This code below is not supported by Microsoft

//Place this code at the start of your script

function setSubgridHeight(grdID, noRecordsDisplay, noRecordsPerPage, forceRefresh) {
/// <summary>
/// Causes sub-grid to scroll by setting the number of records to be displayed and
// </summary>
/// <param name="grdID" type="string">
/// ID of sub-grid *required
/// </param>
/// <param name="noRecordsDisplay" type="int">
/// Controls height of sub-grid and how many recors are displayed
/// Before applying scrolling
/// </param>
/// <param name="noRecordsPerPage" type="int">
/// Determines number of records to display per page.  If not provided
/// The value defined in the form editor will be used
/// </param>
/// <returns type="nothing" />
if (!IsNull(grdID)) {
  var tbl = $("#" + grdID);

  //Adjust the sub-grid page size if desired, otherwise this is controlled by the form editor
  if (!IsNull(noRecordsPerPage)) {
    //Get reference to divGridProps element of desired grid.
    //Microsoft stores property infomrmaiton about the sub-grid within this element
    var divProps = $("#divGridProps", tbl);
    $("#recsPerPage", divProps).attr("value", noRecordsPerPage);
    //Controls number of rows returned by data provider and sets the page size for the sub-grid
  }

  //Get reference to divGridParams element of desired grid.
  //Microsoft stores parameter infomrmaiton about the sub-grid within this element
  var divParams = $("#divGridParams", tbl);
  noRecordsDisplay = (IsNull(noRecordsDisplay) ? "5" : noRecordsDisplay);

  //Default to 5 visible records at a time
  $("#RecordsPerPage", divParams).attr("value", noRecordsDisplay);

  //Controls number of rows displayed in output table
  $("#maxrowsbeforescroll", divParams).attr("value", noRecordsDisplay);
  //Force scroll bar to display if more records included than desired to display

  //Clear all of the empty TR that are added to fill the table height
  var tb = $("#" + grdID + "_d").parent().parent();
  $("tr", tb).filter(function(index) { return $(this).html() == ""; }).remove();

  //Now resize the data area of the grid
  $("#" + grdID + "_divDataArea").css("height", ((noRecordsDisplay - 1) * 25) + "px");

  //Refresh the grid if desired
  if(forceRefresh) { 
    document.getElementById(grdID).control.refresh(); 
  }
} else {
  throw Error.argument("grdID", "grdID is null or undefined");
}

//To use you would write something like
setSubgridHeight(#SUB-GRID ID#, 10, null, false);

Have Fun!

Cheers,
Chris

Veröffentlicht unter Uncategorized | Kommentar hinterlassen

Fehler bei Plugin-Registrierung – The Web Service plug-in failed

Hallo Leute,

nach längerer Abwesenheit mal wieder was neues zum Thema CRM.
Wir mussten einen unserer CRM-Server neu aufsetzen und hatten nach der Registrierung der Plugins schlimme Probleme.

Fehlermeldung (im Eventviewer) war die folgende:

The Web Service plug-in failed in OrganizationId EntityName: sdk message; Stage: 30; MessageName: RetrieveMultiple

Unsere Recherche hat uns schließlich zum Blog von KAUSTUBH GHANEKAR geführt.

Er schreibt:

I registered following dll files from Server/CRMWeb/bin into the Global Assembly Cache of CRM server.

Microsoft.Xrm.Sdk.dll
Microsoft.Crm.Extensibility.dll

Und tatsächlich, das hat das Problem behoben.

Ich hoffe ich konnte euch ein paar Minuten eurer Zeit sparen 🙂

Beste Grüße
Christian

Veröffentlicht unter Betrieb, Dynamics CRM | Verschlagwortet mit , | Kommentar hinterlassen

CRM 2011 – OrganizationRequest – Set Active/Inactive

Hallo Leute,

heute mal was kurzes, was ich hier festhalten möchte, weil nicht in der SDK dokumentiert und im Internet nur schwer zu finden:

http://rajeevpentyala.wordpress.com/2011/10/18/activate-or-deactivate-record-in-crm-2011/

Rajeev Pentyala zeigt in diesem Blog, wie man eine Entität aktiviert bzw. deaktiviert. Die dazu notwendigen Statuscodes sind leider nicht dokumentiert.

private void SetEntityStatus(IOrganizationService service, Guid recordGUID, string entityName)        {

SetStateRequest setState = newSetStateRequest();

setState.EntityMoniker = newEntityReference();

//Pass GUID of the record to be activated or Deactivated

setState.EntityMoniker.Id = recordGUID;

setState.EntityMoniker.Name = entityName;

setState.EntityMoniker.LogicalName = entityName;

//Setting ‘State’ i.e., (0 – Active ; 1 – InActive)

setState.State = new OptionSetValue();

setState.State.Value = 0/1;

//Setting ‘Status’ i.e., (1 – Active ; 2 – InActive)

setState.Status = new OptionSetValue();

setState.Status.Value = 1/2;

SetStateResponse setStateResponse = (SetStateResponse)service.Execute(setState);

}

Cheers,
Chris

Veröffentlicht unter C Sharp, Dynamics CRM | Kommentar hinterlassen

CRM 2011 – Javascript – Attribute setzen (für alle Datentypen)

Hallo Leute,

nach längerer Zeit mal wieder ein feiner Alltags-Helper.
Um in CRM via Javascript einen Wert in ein Attribut schreiben zu können, bedarf es eigentlich je nach Typ (Lookup, Text, Integer, etc.) eine eigene Methode.
Ich habe mir jetzt einen Helper geschrieben, der selbst prüft um was für einen Typ es sich handelt und entsprechend handelt.

this.SetAttributeValue = function (id, value, valueId, logicalName) {

        var control = Xrm.Page.getControl(id);
        var isDisabledField = Xrm.Page.getControl(id).getDisabled();


        if (isDisabledField) {
            Xrm.Page.getControl(id).setDisabled(false);
        }

        try {
            if (control != null) {

                if (value == null) {
                    FormUtils.SetStandardAttributeValue(id, value);
                }
                else {
                    var name = id;
                    var type = control.getAttribute().getAttributeType();

                    switch (type) {

                        case "string":
                            FormUtils.SetStandardAttributeValue(id, value);
                            break;

                        case "integer":
                            var intValue = parseInt(value);
                            FormUtils.SetStandardAttributeValue(id, intValue);
                            break;

                        case "optionset":
                            FormUtils.SetStandardAttributeValue(id, value);
                            break;

                        case "memo":
                            FormUtils.SetStandardAttributeValue(id, value);
                            break;

                        case "boolean":
                            FormUtils.SetStandardAttributeValue(id, (value == "true"));
                            break;

                        case "money":
                            var intValue = parseFloat(value);
                            FormUtils.SetStandardAttributeValue(id, intValue);
                            break;

                        case "datetime":
                            // not implemented yet
                            break;

                        case "lookup":
                            FormUtils.SetLookupAttributeValue(id, valueId, value, logicalName);
                            break;

                        case "decimal":
                            var intValue = parseFloat(value);
                            FormUtils.SetStandardAttributeValue(id, intValue);
                            break;
                    }
                }

            }
        }
        catch (ex) {

        }

        if (isDisabledField) {
            Xrm.Page.getControl(id).setDisabled(true);
        }

    }


    // Setzt den Wert eines "normalen" Attributes auf einer Entity-Page.
    this.SetStandardAttributeValue = function (id, value) {

        var isDisabledField = Xrm.Page.getControl(id).getDisabled();

        if (isDisabledField) {
            Xrm.Page.getControl(id).setDisabled(false);
        }

        try {
            Xrm.Page.getAttribute(id).setValue(value);
            Xrm.Page.getAttribute(id).setSubmitMode('always');
        }
        catch (err) {
            alert(err);
        }

        if (isDisabledField) {
            Xrm.Page.getControl(id).setDisabled(true);
        }
    }

    // Setzt den Wert eines "normalen" Attributes auf einer Entity-Page.
    this.SetLookupAttributeValue = function SetLookupAttributeValue(id, valueId, value, entityLogicalName) {

        var isDisabledField = Xrm.Page.getControl(id).getDisabled();

        if (isDisabledField) {
            Xrm.Page.getControl(id).setDisabled(false);
        }

        try {
            if (value == null) {
                Xrm.Page.getAttribute(id).setValue(value);
            }
            else {
                Xrm.Page.getAttribute(id).setValue([{ id: valueId, name: value, entityType: entityLogicalName}]);
            }
            Xrm.Page.getAttribute(id).setSubmitMode('always');
        }
        catch (err) {

        }

        if (isDisabledField) {
            Xrm.Page.getControl(id).setDisabled(true);
        }
    }

Beim setzen eines Optionsets muss der Integer-Wert gesetzt werden, nicht der Label. Zudem werden für das Setzen des Lookup-Attributes mehrere Parameter benötigt, die bei anderen Datentypen NULL sein können.

Am Error-Handling sollte man noch arbeiten, das ist dann aber euch selbst überlassen 😉

Have Fun!

Cheers,
Christian

Veröffentlicht unter C Sharp, Dynamics CRM, Javascript | Verschlagwortet mit , , | Kommentar hinterlassen

CRM 2011 – ValueRule und OrRule kombinieren

Hallo Leute,

in einem meiner letzten Blogs habe ich mal über die Verwendung von ValueRules geschrieben (Blog). Was aber tun, wenn man zwei oder mehrere Optionen hat, die man mit einem ValueRule abfragen möchte?

Die Antwort habe ich auf Vikranth’s Blog gefunden.

Im wesentlichen ist die Lösung folgendes:

<DisplayRule Id="ShowUndo">
  <OrRule>
    <Or>
      <ValueRule Field="xxx_type" Value="val1"></ValueRule>    
    </Or>
     <Or>
      <ValueRule Field="xxx_type" Value="val2"></ValueRule>    
    </Or>
  </OrRule>
</DisplayRule>

Nicht ganz logisch aber eigentlich recht einfach.

Cheers,
Christian

Veröffentlicht unter C Sharp, XML | Verschlagwortet mit , , | Kommentar hinterlassen

ASP.net – Bitmap (.bmp) in den OutputStream rendern – Render Bitmap into Outputstream

Hallo Leute,

mal wieder was Spannendes. Beim Versuch eine BMP-Grafik direkt in den Outputstream einer ASP.net Webpage zu rendern, tritt eine Exception auf (System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.).

Spannende Geschichte, denn der gleiche Quellcode funktioniert mit JPG-Grafiken:

Response.Clear();
Response.ContentType = "image/jpeg"; // "image/bmp" does not work!

Image orgChartImage = (System.Drawing.Image)Cache[imageName];
orgChartImage.Save(this.Response.OutputStream);
orgChartImage.Dispose();

Bei meiner Recherche bin ich über den Blog von Rick Stahl gestolpert, der das gleiche Problem mit PNG-Grafiken beschreibt, siehe:

Rick Stahl’s Blog

In den Kommentaren schreibt u.a. Russ Garner, dass das daran liegen kann, dass der Encoder von PNG-Grafiken einen bi-directional Stream benötigt und postet gleichzeitig auch die Lösung:

Png’s are a special case. Their encoder requires a bi-directional stream. The solution is to stream to a memory stream first and write the contents of that memory stream to OutputStream afterwards.

When you get to caching (which I’ve just implemented) you’ll be writing to a memory stream anyway just to cache the output, so this isn’t a big deal.

As far as the GIF end of things goes, the default palletization of the built in GIF encoder leaves something to be desired. I’ve built in support for an Octree quantizer to deal with this.

Seriously – it’s a lot of work. It’s probably easier if I just send you some code 😉

Umgemünzt auf unser Beispiel bedeutet dies folgenden Sourcecode:

string imageName = Request.QueryString["ID"];
Bitmap bm2 = (System.Drawing.Bitmap)Cache[imageName];
Bitmap bm3 = new Bitmap(bm2);

MemoryStream ms = new MemoryStream();

Response.ContentType = "image/bmp";
bm3.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
ms.WriteTo(Response.OutputStream);

bm2.Dispose();
bm3.Dispose();
Response.End();

Eine schlüssigere Fehlermeldung wäre mal was gewesen …
Ich hoffe, ich rette euch mit diesen Codesnippets ein paar Stunden eurer wertvollen Zeit!

Cheers,
Chris

Veröffentlicht unter C Sharp, GDI | Verschlagwortet mit , , , | Kommentar hinterlassen

CRM 2011 – OnCloseAlert – „Möchten Sie diese Seite wirklich verlassen?“ entfernen/unterdrücken

Hallo Leute,

einigen von euch ist es sicher schon passiert/aufgefallen. Ihr erzeugt eine neue Entität mittels Formular und wollt dieses Fenster dann, ohne es zu speichern, wieder verlassen. Was folgt ist der nachfolgende Dialog:

Das kann durchaus Sinn machen, möchte man z.B. den Benutzer warnen, dass Änderungen verloren gehen würden. Jedoch ist dieser Dialog durchaus problematisch, z.B. wenn man via Script die Seite neu laden/refreshen möchte und bewusst in Kauf nehmen möchte, dass Änderungen verloren gehen können.

Leider beschreibt die SDK keine Möglichkeit, wie man das deaktivieren kann. Sucht man mittels div. Suchmaschinen, bekommt man höchstens von Oberlehrern gebetsmühlenartig vorgekaut, dass man solche Dialoge tunlichst nicht verwenden soll…

Die Lösung ist letztlich recht einfach und besteht aus einer Zeile Code und kann im Javascript aufgerufen werden, nämlich:

this.DetachCloseAlert = function () {
        crmForm.detachCloseAlert();
    }

Happy Programming!

Cheers,
Chris

Veröffentlicht unter C Sharp, Javascript | Verschlagwortet mit , , | Kommentar hinterlassen

CRM 2011 – Required Fields serverseitig Validieren

Hi Leute,

man kennt doch das Problem, ab und zu schlägt irgendein Javascript fehlt (Syntax-Error, neue Browser-Version, etc.) und schon hat man den Salat, dass z.B. ein User eine Funktion auslöst, zu der er eigentlich nicht berechtigt wäre. Oder dass Felder, welche als Muss bzw. Required definiert sind, nicht ausgefüllt werden. Auf letzteren Punkt möchte ich den Fokus in diesem Blog-Entry legen. Nämlich wie man diese Required-Fields z.B. in einem eigenen WS oder in einem Plugin checkt.

CRM agiert hier, wie so oft, etwas eigenartig. Denn, wenn man sich die SDK so durchsieht, findet man ausschließlich einen ValidateRequest, welcher dann aber leider nur für div. Aktivitäten funktioniert, nicht für „normale“ Entitäten.

Contains the data that is needed to verify that an appointment or service appointment (service activity) has valid available resources for the activity, duration, and site as appropriate.

Warum das so ist, immerhin ist eine Aktivität nichts anderes als eine Entität, ist leider unklar. Also blieb nichts anderes übrig, selbst einen Weg zu finden, was auch relativ einfach gelang.

Zunächst mussten wir alle Required-Fields für eine Entität an Hand der Metainformationen herausfiltern:

 public static List<KeyValuePair<string, string>> GetRequiredFields(contracts.IOrganization organization, Entity entity)
        {
            try
            {
                List<KeyValuePair<string, string>> reqFields = new List<KeyValuePair<string, string>>();

                var metadata = GetAllEntityAttributes(organization, entity.LogicalName);
                foreach (var attribute in metadata)
                {
                    if (attribute.RequiredLevel.Value == AttributeRequiredLevel.ApplicationRequired)
                    {
                        string label = attribute.AttributeOf;
                        if (attribute.DisplayName.UserLocalizedLabel != null)
                            label = attribute.DisplayName.UserLocalizedLabel.Label;


                        reqFields.Add(new KeyValuePair<string, string>(attribute.LogicalName, label));
                    }
                }
                return reqFields;
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

Wir prüfen dabei nur auf „ApplicationRequired„-Fields, was den selbst definierten Pflichtfeldern entspricht. Man könnte noch „SystemRequired“ verwenden, was dann auch Felder wie „ownerid“, etc. zurückliefert. Es gibt noch weitere Optionen, hier lohnt sich der Blick ins CRM-SDK.

ApplicationRequired – The attribute is required to have a value.
None – No requirements are specified.
Recommended – It is recommended that the attribute has a value.
SystemRequired – The attribute is required to have a value.

Letztlich fehlt nur noch jene Methode, die überprüft, ob die gewünschte Entität auch die als required definierten Felder hält. Das funktioniert in CRM sehr einfach, denn die Attribute-Collection eines Microsoft.Xrm.Sdk.Entity-Objekts hält prinzipiell nur jene Attribute, die gesetzt wurden. Fehlt in dieser Collection also ein required Field, wurde es nicht gesetzt:

public static List<KeyValuePair<string, string>> ValidateEntity(IOrganization organization, Entity entity)
        {
            try
            {
                // List<KeyValuePair<string, string>> listOfAlerts = new List<KeyValuePair<string, string>>();
                List<ValidationResult> listOfErrors = new List<ValidationResult>();
                // get required fields
                var reqFields = GetRequiredFields(organization, entity);

                // get displayname from entitymeta
                var meta = GetEntityMeta(organization, entity.LogicalName);
                var displayName = meta.DisplayName.UserLocalizedLabel.Label;

                foreach(var field in reqFields)
                {
                    if(!entity.Attributes.ContainsKey(field.Key))
                        listOfErrors.Add(new ValidationResult(field.Value, displayName, field.Key)); // Entitäts-Label | attribute-label | prefix_attributename
                }

                return listOfErrors;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

Die Methode liefert eine Generic-List retour, welche jene Felder beinhält, welche zwar required sind aber nicht gesetzt wurden.

Happy Programming 😉

Cheers,
Chris

Veröffentlicht unter C Sharp, Dynamics CRM, Webservices | Verschlagwortet mit , , , | Kommentar hinterlassen