Versionen im Vergleich

Schlüssel

  • Diese Zeile wurde hinzugefügt.
  • Diese Zeile wurde entfernt.
  • Formatierung wurde geändert.

Beschreibung

Mit Einstellungen des Interface "IWmsActivitySettingList" kann der WMS-Benutzer mehrere Einstellungen des selben Typs hinterlegen. Über Zuordnungen kann er einzelne dieser Einstellungen dann im Workflow und in Aktivitäten verwenrden.

Die Einstellungen SMTP, FTP und Datenbanken im WMS nutzen dieses Interface. 

Häufige Anwendungsfälle:

  • Allgemeingültige Verbindungseinstellungen zu Drittsystemen oder Geräten

Panel
titleInhalt
toc

Inhalt

Inhalt
minLevel1
maxLevel3


Aufbau des Interface IWmsActivitySettingList

Eigenschaft / Methode

Beschreibung

Identifier

Immer gleicher, eindeutiger Identifier dieser Einstellung!

Title

Titel der Einstellung, wird als Name des Menüs verwendet.

TitleToolTip

Tooltip für das Menü bzw. die Schaltfläche.

DialogContent

UserControl zur Bearbeitung der Einstellung im Dialog.
Erst in InitialiseDialog-Methoden zusammen bauen!

IsValidDialogData()

Prüft, ob die Eingaben im Dialog valide sind. Nur dann wird der Dialog geschlossen.

AddErrorToDialog(string error)

Zeigt eine

Diese Methode soll die angegbene Fehlermeldung im Dialog

an

anzeigen.
Das WMS ruft diese Methode auf, wenn eine Einstellung mit diesem Namen bereits vorhanden ist.

InitialiseDialogData(WmsSettingEntry entry)

Erzeugt die Oberfläche zur Bearbeitung eines Eintrages.

GetDialogData()

Ermittelt die Eingaben aus dem Dialog um sie zu speichern.

Beispiel 

Im Folgenden entwickeln wir eine Aktivität, um Dateien auf einen FTP Server hochzuladen. Der WMS-Benutzer kann beliebig viele FTP-Einstellungen konfigurieren und über die Zuordnungen die

Implementierung IWmsActivitySettingList

IWmsActivitySettingList
Codeblock
languagec#
titleBeispiel IWmsActivitySettingListlinenumberstruecollapse
true
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Controls;
using Accantum.Wms.ActivityContracts.Settings;
using ActivitySample.Activities.FtpUpload.V01;

namespace ActivitySample.Activities.FtpUpload.Setting
{
    public class FtpConfigurationSettings :  IWmsActivitySettingList
    {
        public static Guid SettingId = new Guid("1f2d1198-b5c7-47f9-a8c4-fda02cc49d61");

        // Eindeutiger Identifier dieser Einstellung
        public Guid Identifier => SettingId;

        /// <summary>
        /// Bezeichnung für das Einstellungsmenü
        /// </summary>
        public string Title => "FTP";

        /// <summary>
        /// Tooltip für die Schaltfläche im Einstellungsmenü
        /// </summary>
        public string TitleTooltip => "FTP-Verbindungen verwalten, die in den FTP-Aktivitäten zur Verfügung stehen.";

        /// <summary>
        /// Prefix für Zuordnungsvariablen
        /// </summary>
        public string MappingVariablePrefix => "ftp";

        /// <summary>
        /// Zusätzliche Spalten, die in der Übersicht angezeigt werden sollen
        /// </summary>
        public IEnumerable<WmsSettingColumnDef> ColumnDefinitions => new List<WmsSettingColumnDef>
        {
            new WmsSettingColumnDef("FTP-Host", nameof(WmsFtpConfig.Host)),
            new WmsSettingColumnDef("Verzeichnis", nameof(WmsFtpConfig.RootDirectory))
        };

        /// <summary>
        /// UserControl zur Bearbeitung der Einstellung im Dialog.
        /// </summary>
        public UserControl DialogContent { get; private set; }

        /// <summary>
        /// Prüft, ob die Eingaben im Dialog valide sind. Nur dann wird der Dialog geschlossen
        /// </summary>
        /// <returns>true, wenn der Dialog geschlossen werden darf</returns>
        public Task<bool> IsValidDialogData()
        {
            var oViewModel = (DialogContent as FtpConfig)?.ViewModel;
            return Task.FromResult(oViewModel != null && oViewModel.IsValid());
        }

        /// <summary>
        /// Zeigt eine Fehlermeldung im Dialog an.
        /// </summary>
        /// <param name="a_sPropertyName">Name der fehlerhaften Eigenschaft</param>
        /// <param name="a_sErrorMessage">Fehlermeldung</param>
        public void AddErrorToDialog(string a_sPropertyName, string a_sErrorMessage)
        {
            var oViewModel = (DialogContent as FtpConfig)?.ViewModel;
            oViewModel?.AddErrorToDialog(a_sPropertyName, a_sErrorMessage);
        }

        /// <summary>
        /// Erzeugt die Oberfläche zur Bearbeitung eines Eintrages
        /// </summary>
        /// <param name="a_oSettingEntry"></param>
        public void InitialiseDialogData(WmsSettingEntry a_oSettingEntry)
        {
            var oVm = new FtpConfigViewModel(a_oSettingEntry);
            DialogContent = new FtpConfig(oVm);
        }

        /// <summary>
        /// Ermittelt die Eingaben aus dem Dialog um sie zu speichern
        /// </summary>
        /// <returns></returns>
        public WmsSettingEntry GetDialogData()
        {
            var 
oViewModel
control = 
(
DialogContent as FtpConfig
)?.ViewModel
;
            var viewModel 
return
= 
oViewModel?.GetSettingEntry()
control.ViewModel;
        
}
    //Hier 
}
könnten 
}
das 

Implementierung ViewModel 

Codeblock
languagec#
titleBeispiel FTP Setting-ViewModel
linenumberstrue
collapsetrue
using System.ComponentModel.DataAnnotations; using System.Net
Passwort wieder aus der Passwortbox ermitteln
            viewModel.Password = control.PasswordBox.SecurePassword;
            return viewModel.GetSettingEntry(;
        }
    }
}


WmsFtpConfig: Wert der FTP Einstellung, die gespeichert wird
Codeblock
languagec#
using System;
using System.Security.Authentication;
using System.
Security
Xml.
Authentication
Serialization;
using Accantum.Wms.ActivityContracts.Settings;

using
namespace ActivitySample.Activities.FtpUpload.V01
; using ActivitySample.Helper; using ActivitySample.Properties; namespace ActivitySample.Activities.FtpUpload.Setting {

{
    /// <summary>
    /// Einstellungen zu einem FTP-Account
    /// </summary>
    [Serializable]
    public class 
FtpConfigViewModel : ValidatableModelBase
WmsFtpConfig
    {
        private readonly 
string
WmsSettingEntry m_
sName
oSettingEntry;
        private string m_
sDescription;
strRootDirectory;

        public WmsFtpConfig()
    
private string m_sHost;
    {
            
private
Port 
string
= 
m_sUsername;
null;
        }

      
private SecureString m_sPassword;
  public WmsFtpConfig(WmsSettingEntry a_oSettingEntry)
        
private
{
int?
 
m_iPort;
         
private
 
EFtpEncryptionMode
 m
_eEncryptionMode;
_oSettingEntry = a_oSettingEntry;
            
private
Id 
SslProtocols
= 
m
a_
eEncryptionProtocol;
oSettingEntry.Id;
            
private
Name 
string
= 
m
a_
sRootDirectory
oSettingEntry.Name;

       
private
 
bool
 
m_bIsBusy;
   //Eigenschaften aus dem Properites-Array laden
 
private
 
string
 
m_sConnectionStateInfo;
         Host 
private readonly WmsSettingEntry m_oSettingEntry
= a_oSettingEntry.Properties[nameof(Host)] as string;
         
public FtpConfigViewModel(WmsSettingEntry
   Port = a_oSettingEntry.Properties[nameof(Port)] as int?;
      
{
      
m_oSettingEntry
User = a_oSettingEntry
?? new WmsSettingEntry();
.Properties[nameof(User)] as string;
            EncryptedPassword 
SetProperties();
= a_oSettingEntry.Properties[nameof(EncryptedPassword)] as string;
            
}
EncryptionMode = a_oSettingEntry.Properties[nameof(EncryptionMode)] as EFtpEncryptionMode? ?? EFtpEncryptionMode.AutoDetect;
   
#region
 
Properties
        EncryptionProtocol = 
[Required
a_oSettingEntry.Properties[nameof(EncryptionProtocol)] as SslProtocols? ?? SslProtocols.None;

    
public
  
string
 
Name
     RootDirectory = a_oSettingEntry.Properties[nameof(RootDirectory)] as string;
{
        }

   
get
 
=>
 
m_sName;
   /// <summary>
        
set => SetProperty(ref m_sName, value);
/// Eindeutige Id aus der Einstellung
        
}
/// </summary>
        public 
string
Guid 
Description
Id { get; set; }

   
{
     /// <summary>
      
get
 
=> m_sDescription;
 /// Name aus der Einstellung
        
set => SetProperty(ref m_sDescription, value);
/// </summary>
        public string Name 
}
{ get; set; }

      
[Required,
 
Display(ResourceType = typeof(Resource), Name = "Host")]
 /// <summary>
        /// FTP-Host für 
public
den 
string
Datenaustausch
Host
        
{
/// </summary>
        public string Host { get
=> m_sHost;
; set; }

        /// <summary>
  
set
 
=>
 
SetProperty(ref
 
m_sHost,
 
value);
  /// Port, welcher für den FTP-Zugang verwendet 
}
wird. Wenn nicht gesetzt, dann werden die Standardports verwendet
 
[Display(ResourceType
 
=
 
typeof(Resource),
 
Name
 
=
 
"Username")]
  /// Standardwert: null
    
public
 
string
 
Username
  /// </summary>
     
{
   public int? Port { get; set; }

  
get
 
=>
 
m_sUsername;
    /// <summary>
       
set
 
=> SetProperty(ref m_sUsername, value);
/// Benutzer des FTP-Zugangs.
        
}
/// </summary>
        public 
SecureString
string 
Password
User { get; set; }

   
{
     /// <summary>
      
get
 
=> m_sPassword;
 /// Passwort des FTP-Zugangs
        
set => SetProperty(ref m_sPassword, value);
/// </summary>
        [XmlElement("Password")]
   
}
     public string EncryptedPassword { get; 
public
set; 
int?
}
Port

        
{
/// <summary>
        /// Modus der 
get => m_iPort;
Verschlüsselung (none, explizit, implizit).
        /// </summary>
 
set
 
=>
 
SetProperty(ref
 
m_iPort,
 
value);
   public EFtpEncryptionMode EncryptionMode { get; set; }

        /// 
public
<summary>
EFtpEncryptionMode
 
EncryptionMode
       /// Protokoll 
{
der Verschlüsselung (SSL -Secure Sockets Layer, TLS).
      
get
 
=> m_eEncryptionMode;
 /// </summary>
        public SslProtocols EncryptionProtocol { get; set; }

        /// <summary>
{
        /// Basis-Verzeichnis auf dem FTP-Server (Verzeichnisse mit "/" getrennt, 
SetProperty(ref m_eEncryptionMode, value);
nicht mit "\")
        /// </summary>
        
if
public 
(value
string 
== EFtpEncryptionMode.AutoDetect)
RootDirectory
        {
            
EncryptionProtocol
get =
SslProtocols.None
> m_strRootDirectory;
            
}
set
        
}
    {
     
public
 
SslProtocols
 
EncryptionProtocol
         
{
if (value != null)
         
get
 
=>
 
m_eEncryptionProtocol;
     {
       
set
 
=>
 
SetProperty(ref
 
m_eEncryptionProtocol,
 
value);
         
}
string strPath = value.Replace('\\', '/');
      
[Display(ResourceType
 
=
 
typeof(Resource),
 
Name
 
=
 
"RootDirectoryName")]
         
public
m_strRootDirectory = (string
RootDirectory
.IsNullOrEmpty(strPath) || strPath.StartsWith("/")) ? strPath : $"/{strPath}";
   
{
             
get
}
=>
 
m_sRootDirectory;
             
set
 
=>
 
SetProperty(ref m_sRootDirectory, value);
else
          
}
      {
            
public
 
bool
 
IsBusy
      m_strRootDirectory = null;
{
             
get
 
=>
 
m_bIsBusy;
 }
           
set
 
=>
}
SetPropertyWithoutValidate(ref
 
m_bIsBusy,
 
value);
      }

 
}
       /// <summary>
 
public
 
string
 
ConnectionStateInfo
     /// Um Einstellung zu 
{
speichern in ein WmsSettingEntry wandeln und die zu speichernden Eigenschaften in das Properties-Array 
get
schreiben
=>
 
m_sConnectionStateInfo;
       /// </summary>
    
set => SetPropertyWithoutValidate(ref
 
m_sConnectionStateInfo,
 
value);
  public WmsSettingEntry ToWmsSettingEntry()
    
}
    {
     
#endregion
       return new WmsSettingEntry
 
public
 
bool
 
IsValid()
         {
              
return
 
ValidateObject();
 Id = m_oSettingEntry.Id,
     
}
          
public
 
void
Name 
AddErrorToDialog(string
= 
a
m_
sPropertyName
oSettingEntry.Name,
string
 
a_sErrorMessage)
         
{
      Description = m_oSettingEntry.Description,
    
AddError(a_sPropertyName,
 
a_sErrorMessage);
         
}
  CreationDate = m_oSettingEntry.CreationDate,
             
public
 
WmsFtpConfig
 
CreateFtpConfig()
 CreationUser = m_oSettingEntry.CreationUser,
     
{
           ModifyDate = m_oSettingEntry.
Name = Name;
ModifyDate,
                ModifyUser = m_oSettingEntry.
Description = Description;
ModifyUser,
          
var
 
sPasswortString
 
=
 
new
 
NetworkCredential(string.Empty,
 
Password).Password;
 Properties = new WmsPropertyCollection
         
var
 
oConfig
 
=
 
new
 
WmsFtpConfig(m_oSettingEntry)
   {
         
{
           new WmsSettingEntryProperty(nameof(Host), Host),
   
Host =
 
Host,
                new 
Port =
WmsSettingEntryProperty(nameof(Port), Port),
                
User
 
=
 
Username,
  new WmsSettingEntryProperty(nameof(User), User),
            
EncryptedPassword
 
=
 
sPasswortString,
 
//Hier
 
Verschlüsseln!
 
z.B.
 
TripleDES
  new WmsSettingEntryProperty(nameof(EncryptedPassword), EncryptedPassword),
            
EncryptionMode
 
=
 
EncryptionMode,
      new 
WmsSettingEntryProperty(nameof(EncryptionMode), EncryptionMode),
      
EncryptionProtocol
 
= EncryptionProtocol,
             new WmsSettingEntryProperty(nameof(EncryptionProtocol), EncryptionProtocol),
 
RootDirectory
 
=
 
RootDirectory
             
};
    new WmsSettingEntryProperty(nameof(RootDirectory), RootDirectory)
      
return
 
oConfig;
         }
         
public
 
WmsSettingEntry
 
GetSettingEntry()
 };
       
{
 }
    }
}


Implementierung der Oberfläche zur Eingabe der Einstellung

ViewModel des FTP-Dialogs
Codeblock
languagec#
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Security;
var oFtpConfig = CreateFtpConfig(); return oFtpConfig.ToWmsSettingEntry(); } private void SetProperties() { var oFtp = new WmsFtpConfig(m_oSettingEntry);
using System.Security.Authentication;
using Accantum.Wms.ActivityContracts.Settings;
using ActivitySample.Activities.FtpUpload.V01;
using ActivitySample.Helper;
using ActivitySample.Properties;

namespace ActivitySample.Activities.FtpUpload.Setting
{
    // ViewModel für die Bearbeitung einer FTP-Verbindungseinstellung
    // Accantum verwendet in seinen ViewModel eine Klasse "ValidatableModelBase". Diese implementiert u.a. INotifyPropertyChanged.
    // Für externe Entwicklungen steht die Klasse nicht zur Verfügung. Beispiele von Microsoft: https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/how-to-implement-property-change-notification?view=netframeworkdesktop-4.8
    public class FtpConfigViewModel : ValidatableModelBase
    {
        private string m_sName
= m_oSettingEntry.Name
;
        private 
string m_sDescription;
= m_oSettingEntry.Description;
        private string m_sHost;
     
var
 
oSecurePassword
 
=
 
new
private 
NetworkCredential(
string
.Empty, oFtp.EncryptedPassword).SecurePassword; //Hier Entschlüsseln
 m_sUsername;
        private SecureString m_sPassword;
     
m_sHost
  
=
 
oFtp.Host;
private int? m_iPort;
        private EFtpEncryptionMode m_
sUsername = oFtp.User
eEncryptionMode;
        private 
SslProtocols m_
sPassword = oSecurePassword
eEncryptionProtocol;
        private string 
m_
iPort = oFtp.Port
sRootDirectory;
        private 
bool m_
eEncryptionMode = oFtp.EncryptionMode
bIsBusy;
        private 
string m_
eEncryptionProtocol = oFtp.EncryptionProtocol
sConnectionStateInfo;

        private readonly WmsSettingEntry m_
sRootDirectory = oFtp.RootDirectory
oSettingEntry;

       
}
 public FtpConfigViewModel(WmsSettingEntry a_oSettingEntry)
 
}
 
}
  
Codeblock
languagec#
titleWmsFtpConfig: Wert der FTP Einstellung, die gespeichert wird
linenumberstrue
collapsetrue
using
 
System;
 
using
 
System.Security.Authentication; using
 
System.Xml.Serialization; using Accantum.Wms.ActivityContracts.Settings; namespace ActivitySample.Activities.FtpUpload.V01
{
   
///
 
<summary>
     
///
 
Einstellungen
 
zu
 
einem FTP-Account /// </summary>
m_oSettingEntry = a_oSettingEntry ?? new WmsSettingEntry();
      
[Serializable]
     
public
 
class
SetProperties();
WmsFtpConfig
     
{
   }

    
private
 
readonly
 
WmsSettingEntry
 
m_oSettingEntry;
 #region Properties

     
private
 
string
 
m_strRootDirectory;
 [Required]
        public 
WmsFtpConfig()
string Name
        {
            
Port
get => 
null
m_sName;
          
}
  set => SetProperty(ref m_sName, value);
   
public
 
WmsFtpConfig(WmsSettingEntry
 
a_oSettingEntry)
   }

    
{
    public string Description
      
m_oSettingEntry
 
=
 
a_oSettingEntry;
{
            
Id
get => 
a
m_
oSettingEntry.Id
sDescription;
            
Name
set => SetProperty(ref 
a_oSettingEntry.Name;
m_sDescription, value);
        }

       
//Eigenschaften aus dem Properites-Array laden
 [Required, Display(ResourceType = typeof(Resource), Name = "Host")]
        public string Host
  
= a_oSettingEntry.Properties[nameof(Host)] as string;
      {
            
Port
get => 
a_oSettingEntry.Properties[nameof(Port)] as int?
m_sHost;
            
User
set => 
a_oSettingEntry.Properties[nameof(User)] as string;
SetProperty(ref m_sHost, value);
        }

        
EncryptedPassword
[Display(ResourceType = 
a_oSettingEntry.Properties[nameof(EncryptedPassword
typeof(Resource), Name = "Username")]
as
 
string;
       public string Username
   
EncryptionMode
 
=
 
a_oSettingEntry.Properties[nameof(EncryptionMode)]
 
as
 
EFtpEncryptionMode?
 
?? EFtpEncryptionMode.AutoDetect;
{
            
EncryptionProtocol
get => 
a_oSettingEntry.Properties[nameof(EncryptionProtocol)] as SslProtocols? ?? SslProtocols.None;
m_sUsername;
            set => SetProperty(ref m_sUsername, value);
      
RootDirectory
 
= a_oSettingEntry.Properties[nameof(RootDirectory)] as string;
 }

        public SecureString 
}
Password
        {
///
 
<summary>
         
///
 
Eindeutige
 
Id
get 
aus der Einstellung
=> m_sPassword;
         
///
 
</summary>
  set => SetProperty(ref m_sPassword, value);
  
public
 
Guid
 
Id
 
{
 
get;
 
set;
 }

        
/// <summary>
public int? Port
        
///
{
Name
 
aus
 
der
 
Einstellung
         
/// </summary>
get => m_iPort;
       
public
 
string
 
Name
 
{
 
get;
 set
;
 
}
=> SetProperty(ref m_iPort, value);
      
///
 
<summary>
 
}

     
/// FTP-Host für den Datenaustausch
   public EFtpEncryptionMode EncryptionMode
       
/// </summary>
 {
        
public
 
string
 
Host
 
{
 get
; set
 => m_eEncryptionMode;
}
          
///
 
<summary>
 set
       
///
 
Port,
 
welcher
 
für
 
den
 
FTP-Zugang
{
verwendet
 
wird.
 
Wenn
 
nicht
 
gesetzt,
 
dann
 
werden
 
die
 
Standardports
 
verwendet
       SetProperty(ref 
/// Standardwert: null
m_eEncryptionMode, value);
           
///
 
</summary>
    if (value == EFtpEncryptionMode.AutoDetect)
 
public
 
int?
 
Port
 
{
 
get;
 
set;
 
}
          
///
 
<summary>
  EncryptionProtocol = SslProtocols.None;
    
///
 
Benutzer
 
des
 
FTP-Zugangs.
     }
   
///
 
</summary>
    }

   
public
 
string
 
User
 
{
 
get;
 
set;
public 
}
SslProtocols EncryptionProtocol
        
///
{
<summary>
         
///
 
Passwort
 
des
 
FTP-Zugangs
get => m_eEncryptionProtocol;
      
///
 
</summary>
     set => SetProperty(ref 
[XmlElement("Password")]
m_eEncryptionProtocol, value);
        
public
}
string

EncryptedPassword
 
{
 
get;
 
set;
 
}
    [Display(ResourceType = typeof(Resource), Name = 
/// <summary>
"RootDirectoryName")]
        public string 
///
RootDirectory
Modus
 
der
 
Verschlüsselung
 
(none,
 
explizit, implizit).
    {
    
///
 
</summary>
       get 
public EFtpEncryptionMode EncryptionMode { get; set; }
=> m_sRootDirectory;
            set => 
/// <summary>
SetProperty(ref m_sRootDirectory, value);
        
///
}
Protokoll
 
der
 
Verschlüsselung
 
(SSL
 
-Secure
 
Sockets
 
Layer,
 
TLS).
 

      
///
 
</summary>
 public bool IsBusy
     
public
 
SslProtocols
 
EncryptionProtocol
 {
get;
 
set;
 
}
          
/// <summary>
get => m_bIsBusy;
       
///
 
Basis-Verzeichnis
 
auf
 
dem
 
FTP-Server
 
(Verzeichnisse
set 
mit "/" getrennt, nicht mit "\")
=> SetPropertyWithoutValidate(ref m_bIsBusy, value);
        
/// </summary>
}

        public string 
RootDirectory
ConnectionStateInfo
        {
            get => m_
strRootDirectory
sConnectionStateInfo;
            set => SetPropertyWithoutValidate(ref m_sConnectionStateInfo, value);
        
{
}

        #endregion


    
if
 
(value
 
!=
 
null)
 public 
bool IsValid()
        
{
            
string strPath = value.Replace('\\', '/'
return ValidateObject();
        }

        public void 
m_strRootDirectory = (string.IsNullOrEmpty(strPath) || strPath.StartsWith("/")) ? strPath : $"/{strPath}";
AddErrorToDialog(string a_sPropertyName, string a_sErrorMessage)
        {
           
}
 AddError(a_sPropertyName, a_sErrorMessage);
        }
     
else
   
        public WmsFtpConfig CreateFtpConfig()
  
{
      
{
            m_
strRootDirectory
oSettingEntry.Name = 
null
Name;
            m_oSettingEntry.Description = Description;

}
            var 
}
sPasswortString = new NetworkCredential(string.Empty, Password).Password;

   
}
         var 
///
oConfig 
<summary>
= new WmsFtpConfig(m_oSettingEntry)
      
///
 
Um
 
Einstellung
 
zu
 
speichern
 
in
 
ein
{
WmsSettingEntry
 
wandeln
 
und
 
die
 
zu
 
speichernden
 
Eigenschaften
 
in
 
das
 
Properties-Array
 
schreiben
      Host = Host,
///
 
</summary>
         
public
 
WmsSettingEntry
 
ToWmsSettingEntry()
    Port = Port,
  
{
             
return
 
new WmsSettingEntry
User = Username,
  
{
              EncryptedPassword = sPasswortString, 
Id = m_oSettingEntry.Id,
//Hier Verschlüsseln! z.B. TripleDES
                
Name
EncryptionMode = 
m_oSettingEntry.Name
EncryptionMode,
                
Description
EncryptionProtocol = 
m_oSettingEntry.Description
EncryptionProtocol,
                
CreationDate
RootDirectory = 
m_oSettingEntry.CreationDate,
RootDirectory
            };
   
CreationUser
 
=
 
m_oSettingEntry.CreationUser,
       return oConfig;
        
ModifyDate
}
=

m_oSettingEntry.ModifyDate,
        public WmsSettingEntry GetSettingEntry()
      
ModifyUser
 
= m_oSettingEntry.ModifyUser,
 {
            var oFtpConfig = CreateFtpConfig();
Properties
 
=
 
new
 
WmsPropertyCollection
         return oFtpConfig.ToWmsSettingEntry();
      
{
  }

        
        
new WmsSettingEntryProperty(nameof(Host), Host),
private void SetProperties()
        {
            var oFtp = new 
WmsSettingEntryProperty(nameof(Port), Port),
WmsFtpConfig(m_oSettingEntry);
            m_sName = m_oSettingEntry.Name;
        
new
 
WmsSettingEntryProperty(nameof(User),
 
User),
  m_sDescription = m_oSettingEntry.Description;

            var oSecurePassword = new 
WmsSettingEntryProperty(nameof(EncryptedPassword)
NetworkCredential(string.Empty, oFtp.EncryptedPassword)
,
.SecurePassword; //Hier Entschlüsseln

            m_sHost = oFtp.Host;
      
new WmsSettingEntryProperty(nameof(EncryptionMode), EncryptionMode),
      m_sUsername = oFtp.User;
            m_sPassword = oSecurePassword;
  
new
 
WmsSettingEntryProperty(nameof(EncryptionProtocol),
 
EncryptionProtocol),
        m_iPort = oFtp.Port;
            
new WmsSettingEntryProperty(nameof(RootDirectory), RootDirectory)
m_eEncryptionMode = oFtp.EncryptionMode;
            m_eEncryptionProtocol = oFtp.EncryptionProtocol;
 
}
           m_sRootDirectory = 
}
oFtp.RootDirectory;
        }
    }
}

Implementierung


Oberfläche
CodeblocklanguageymltitleSetting Control
zur Eingabe der FTP-Einstellung
linenumbers
Codeblock
truetrue
language
collapse
yml
<UserControl x:Class="ActivitySample.Activities.FtpUpload.Setting.FtpConfig"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:enums="clr-namespace:ActivitySample.Activities.FtpUpload.V01"
             xmlns:settings="clr-namespace:ActivitySample.Activities.FtpUpload.Setting"
             xmlns:helper="clr-namespace:ActivitySample.Helper"
             xmlns:resx="clr-namespace:ActivitySample.Properties"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="500"
             d:DataContext="{d:DesignInstance {x:Type settings:FtpConfigViewModel}}">
    <UserControl.Resources>
        <ResourceDictionary>
            <helper:InvertedBooleanConverter x:Key="InvertedBooleanConverter"/>

            <Style x:Key="TextareaStyle" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
                <Style.Setters>
                    <Setter Property="AcceptsTab" Value="False" />
                    <Setter Property="AcceptsReturn" Value="True" />
                    <Setter Property="TextWrapping" Value="Wrap" />
                    <Setter Property="SpellCheck.IsEnabled" Value="True" />
                    <Setter Property="VerticalContentAlignment" Value="Top" />
                    <Setter Property="VerticalScrollBarVisibility" Value="Auto" />
                </Style.Setters>
            </Style>
        </ResourceDictionary>
    </UserControl.Resources>

    <Grid Margin="2" IsEnabled="{Binding ElementName=BusyIndicator, Path=IsBusy, Converter={StaticResource InvertedBooleanConverter}}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*" MinWidth="300" MaxWidth="500"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="{x:Static resx:Resource.Name}"/>
        <!--UpdateSourceTrigger ist nötig, um gleich bei Änderungen Speichern-Button zu aktivieren-->
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>

        <Label Grid.Row="1" Grid.Column="0" Content="{x:Static resx:Resource.Description}"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}"
                 Style="{StaticResource TextareaStyle}" MinLines="2" MaxLines="4"/>

        <Label Grid.Row="2" Grid.Column="0" Content="{x:Static resx:Resource.Host}"/>
        <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Host, UpdateSourceTrigger=PropertyChanged}"/>

        <Label Grid.Row="3" Grid.Column="0" Content="{x:Static resx:Resource.Port}"/>
        <!--Hier ist auch ein Control denkbar, (das WMS nutzt Controls von Telerik) telerik:RadNumericUpDown-->
        <TextBox Grid.Row="3" Grid.Column="1" Width="80" HorizontalAlignment="Left" Text="{Binding Port, UpdateSourceTrigger=PropertyChanged}"/>

        <Label Grid.Row="4" Grid.Column="0" Content="{x:Static resx:Resource.Username}"/>
        <TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}"/>

        <Label Grid.Row="5" Grid.Column="0" Content="{x:Static resx:Resource.Password}"/>
        <PasswordBox Grid.Row="5" Grid.Column="1" x:Name="PasswordBox"></PasswordBox>

        <Label Grid.Column="0" Grid.Row="6" Content="{x:Static resx:Resource.Ftp_EncryptionMode}" ToolTip="{x:Static resx:Resource.Ftp_EncryptionModeDesc}"/>
        <ComboBox Grid.Column="1" Grid.Row="6"
                  SelectedValue="{Binding EncryptionMode}"
                  ItemsSource="{Binding Source={helper:EnumToItemsSource {x:Type enums:EFtpEncryptionMode}}}"
                  DisplayMemberPath="DisplayName" SelectedValuePath="Value" />


        <Label Grid.Row="7" Grid.Column="0" Content="{x:Static resx:Resource.RootDirectoryName}"/>
        <TextBox Grid.Row="7" Grid.Column="1" Text="{Binding RootDirectory, UpdateSourceTrigger=PropertyChanged}"/>
        
    </Grid>
</UserControl>
Codeblocklanguagec#title


Beispiel Setting Control - CodeBehind (xaml.cs)
Codeblock
languagec#
using System.Net;
using System.Windows.Controls;

namespace ActivitySample.Activities.FtpUpload.Setting
{
    /// <summary>
    /// Interaction logic for FtpSettings.xaml
    /// </summary>
    public partial class FtpConfig: UserControl
    {
        public FtpConfig(FtpConfigViewModel a_oViewModel)
        {
            InitializeComponent();
            DataContext = a_
oViewModel;
oViewModel;
            //Die Passwordbox lässt kein Binding zu, daher hier setzen
            PasswordBox.Password = new NetworkCredential(string.Empty, a_oViewModel.Password).Password;
        }

        public FtpConfigViewModel ViewModel => DataContext as FtpConfigViewModel;
    }
}

Verwendung in der Aktivität

Codeblocklanguage

c#title
Beispiel zur Verwendung in der Aktivität
linenumbers
Codeblock
truetrue
language
collapse
c#
using System;
using System.Activities;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Authentication;
using Accantum.Wms.ActivityContracts;
using Accantum.Wms.ActivityContracts.Attributes;
using Accantum.Wms.ActivityContracts.Settings;
using ActivitySample.Activities.FtpUpload.Setting;
using ActivitySample.Images;
using ActivitySample.Properties;

namespace ActivitySample.Activities.FtpUpload.V01
{
    /// <summary>
    /// Mit dieser Aktivität kann eine Datei auf einen FTP-Server hochgeladen werden.
    /// BEISPIEL für eine Aktivität mit mehreren Einstellungen (<see cref="IWmsActivitySettingList"/>
    /// </summary>
[ActivityGroup("Acc-Demo")] [LocalizedDisplayName("FtpUpload_DisplayName",

typeof(Resource))]
    [
LocalizedDescription("FtpUpload_Description", typeof(Resource), 1)] [
Designer(typeof(FtpUploadDesigner))]
    [ActivitySettingsType(typeof(FtpConfigurationSettings))]
    
[ToolboxBitmap(typeof(EmbeddedImageType), @"logo16x16.png")]
public sealed class FtpUploadActivity : CodeActivity
    {
        public FtpUploadActivity()
        {
            DisplayName = Resource.FtpUpload_DisplayName;
            CreateTargetDir = true;
        }

        /// <summary>
        /// Id der Konfiguration des FTP-Server-Zugangs (aus einer Zuordnung)
        /// </summary>
        [LocalizedDisplayName("Ftp_FtpConfig", typeof(Resource))]
        [LocalizedDescription("Ftp_FtpConfigDesc", typeof(Resource))]
        [LocalizedCategory("PropertyView_Category_Setting", typeof(Resource))]
        [ExcludeInAnnotation]
        public InArgument<Guid> FtpConfig { get; set; }

        /// <summary>
        /// Verzeichnis der Quelldatei
        /// </summary>
        [LocalizedDisplayName("SourceDirectory", typeof(Resource))]
        [LocalizedDescription("SourceDirectoryDesc", typeof(Resource))]
        [LocalizedCategory("PropertyView_Category_Input", typeof(Resource))]
        public InArgument<string> SourceDirectory { get; set; }

        /// <summary>
        /// Name der Quelldatei 
        /// </summary>
        [LocalizedDisplayName("SourceFilename", typeof(Resource))]
        [LocalizedDescription("SourceFilenameDesc", typeof(Resource))]
        [LocalizedCategory("PropertyView_Category_Input", typeof(Resource))]
        public InArgument<string> SourceFilename { get; set; }

        /// <summary>
        /// FTP-Verzeichnis in welches die Datei hochgeladen wird
        /// </summary>
        [LocalizedDisplayName("Ftp_FtpDirectory", typeof(Resource))]
        [LocalizedDescription("FtpUpload_FtpDirectoryDesc", typeof(Resource))]
        [LocalizedCategory("PropertyView_Category_Input", typeof(Resource))]
        public InArgument<string> FtpDirectory { get; set; }

        /// <summary>
        /// Kennzeichen, ob die Verzeichnisstrukur der Zieldatei angelegt werden soll,
        /// wenn diese nicht existiert.
        /// </summary>
        [LocalizedDisplayName("CreateTargetDir", typeof(Resource))]
        [LocalizedDescription("CreateTargetDirDesc", typeof(Resource))]
        [LocalizedCategory("PropertyView_Category_Input", typeof(Resource))]
        public bool CreateTargetDir { get; set; }

        /// <summary>
        /// Kennzeichen, ob eine bereits existierende Zieldatei überschrieben werden soll.
        /// </summary>
        [DefaultValue(false)]
        [LocalizedDisplayName("OverrideExistingFile", typeof(Resource))]
        [LocalizedDescription("OverrideExistingFileDesc", typeof(Resource))]
        [LocalizedCategory("PropertyView_Category_Input", typeof(Resource))]
        public bool OverrideExistingFile { get; set; }


        protected override void CacheMetadata(CodeActivityMetadata a_oMetadata)
        {
            if (FtpConfig?.Expression == null)
                a_oMetadata.AddValidationError(Resource.Ftp_FtpConfig);
            if (SourceFilename?.Expression == null)
                a_oMetadata.AddValidationError(Resource.SourceFilename);
            if (SourceDirectory?.Expression == null)
                a_oMetadata.AddValidationError(Resource.SourceDirectory);

            base.CacheMetadata(a_oMetadata);
        }

        protected override void Execute(CodeActivityContext a_oContext)
        {
            WmsFtpConfig oFtpConfig = ResolveFptConfig(a_oContext, FtpConfig?.Get(a_oContext));

            string sDirectory = SourceDirectory.Get(a_oContext);
            string sFileName = SourceFilename.Get(a_oContext);

            //Hochzuladende Datei prüfen
            FileInfo oSourceFile = new FileInfo(Path.Combine(sDirectory, sFileName));
            CheckFileInfo(a_oContext, oSourceFile);

            string strFtpDirectory = FtpDirectory.Get(a_oContext);

            using (WmsFtpClient oFtpClient = new WmsFtpClient(oFtpConfig))
            {
                if (!oFtpClient.UploadFile(oSourceFile, strFtpDirectory, CreateTargetDir, OverrideExistingFile))
                    throw new Exception($"FTP-Server: Fehler bei Hochladen der Datei.{Environment.NewLine}{oFtpClient.LastError}");
            }
        }


        /// <summary>
        /// Prüft, ob die Datei existiert und ob der Mandant darauf zugreifen darf.
        /// </summary>
        /// <param name="a_oContext"></param>
        /// <param name="a_oFileInfo"></param>
        private void CheckFileInfo(CodeActivityContext a_oContext, FileInfo a_oFileInfo)
        {
            if (string.IsNullOrEmpty(a_oFileInfo.FullName))
                throw new Exception("Es wurde kein Dateiname angegeben.");

            // Prüfen, ob die  Datei in einem gültigen Mandantenverzeichnis liegt
            var oWmsApi = a_oContext.GetExtension<IWmsApiExtension>();
            if (!oWmsApi.IsInTenantFolder(a_oFileInfo, a_oContext))
                throw new AuthenticationException("Auf das angegebene Verzeichnis darf nicht zugegriffen werden.");


            if (!a_oFileInfo.Exists)
                throw new Exception($"Die Datei {a_oFileInfo.FullName} existiert nicht.");
        }

        /// <summary>
        /// FTP-Einstellung ermitteln
        /// </summary>
        public static WmsFtpConfig ResolveFptConfig(ActivityContext a_oContext, Guid? a_gSettingEntryId)
        {
            //Einstellung aus dem ActivityContext ermitteln, dazu ist der Identifier des Settings notwendig
            WmsSettingsCollection oExtension = a_oContext.GetExtension<WmsSettingsCollection>();
            //In den SettingEntries suchen, ob ein Eintrag mit der Id vorhanden ist.
            WmsSettingEntry oSettingEntry = oExtension[FtpConfigurationSettings.SettingId]?.SettingEntries?.FirstOrDefault(s => s.Id == a_gSettingEntryId);

            if (oSettingEntry == null)
                throw new Exception($"Einstellung mit Id {a_gSettingEntryId} ist nicht vorhanden!");
            
            return new WmsFtpConfig(oSettingEntry);
        }
    }
}

Codeblocklanguageymltitle


Designer zur FTP Aktivität
linenumbers
Codeblock
true
language
collapse
yml
true
<sap:ActivityDesigner x:Class="ActivitySample.Activities.FtpUpload.V01.FtpUploadDesigner"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
    xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
    xmlns:converters="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    xmlns:resx="clr-namespace:ActivitySample.Properties"
    xmlns:v01="clr-namespace:ActivitySample.Activities.FtpUpload.V01"
    xmlns:theme="clr-namespace:Accantum.Wms.ActivityContracts.Theme;assembly=WmsActivityContracts">

    <sap:ActivityDesigner.Resources>
        <converters:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />

        <DataTemplate x:Key="ExpandedTemplate" DataType="v01:FtpUploadDesigner">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Label Grid.Column="0" Grid.Row="0" Content="{x:Static resx:Resource.Ftp_FtpConfig}" 
                       ToolTip="{x:Static resx:Resource.Ftp_FtpConfigDesc}"/>
                <sapv:ExpressionTextBox Grid.Column="1" Grid.Row="0"
                                        OwnerActivity="{Binding ModelItem}"
                                        Expression="{Binding Path=ModelItem.FtpConfig, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
                                        ExpressionType="system:Guid"/>

                <Label Grid.Column="0" Grid.Row="1" Content="{x:Static resx:Resource.SourceDirectory}" 
                       ToolTip="{x:Static resx:Resource.SourceDirectoryDesc}"/>
                <sapv:ExpressionTextBox Grid.Column="1" Grid.Row="1"
                                        OwnerActivity="{Binding ModelItem}"
                                        Expression="{Binding Path=ModelItem.SourceDirectory, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
                                        ExpressionType="system:String"/>

                <Label Grid.Column="0" Grid.Row="2" Content="{x:Static resx:Resource.SourceFilename}" 
                       ToolTip="{x:Static resx:Resource.SourceFilenameDesc}"/>
                <sapv:ExpressionTextBox Grid.Column="1" Grid.Row="2"
                                        OwnerActivity="{Binding ModelItem}"
                                        Expression="{Binding Path=ModelItem.SourceFilename, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
                                        ExpressionType="system:String"/>

                <Label Grid.Column="0" Grid.Row="3" Content="{x:Static resx:Resource.Ftp_FtpDirectory}" 
                       ToolTip="{x:Static resx:Resource.FtpUpload_FtpDirectoryDesc}"/>
                <sapv:ExpressionTextBox Grid.Column="1" Grid.Row="3"
                                        OwnerActivity="{Binding ModelItem}"
                                        Expression="{Binding Path=ModelItem.FtpDirectory, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
                                        ExpressionType="system:String"/>

                <Label Grid.Column="0" Grid.Row="4" Content="{x:Static resx:Resource.Options}"/>
                <StackPanel Grid.Column="1" Grid.Row="4" Orientation="Horizontal">
                    <CheckBox Content="{x:Static resx:Resource.OverrideExistingFile}"
                              IsChecked="{Binding Path=ModelItem.OverrideExistingFile, Mode=TwoWay}" />
                    <CheckBox Content="{x:Static resx:Resource.CreateTargetDir}"
                              IsChecked="{Binding Path=ModelItem.CreateTargetDir, Mode=TwoWay}" />
                </StackPanel>
            </Grid>
        </DataTemplate>

        <Style x:Key="ExpandOrCollapsedStyle" TargetType="{x:Type ContentPresenter}">
            <Setter Property="ContentTemplate" Value="{x:Static theme:WmsActivityTheme.CollapsedTemplate}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=ShowExpanded}" Value="true">
                    <Setter Property="ContentTemplate" Value="{StaticResource ExpandedTemplate}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

    </sap:ActivityDesigner.Resources>

    <ContentPresenter Style="{StaticResource ExpandOrCollapsedStyle}" Content="{Binding}"/>

</sap:ActivityDesigner>