I had a working code using Java using this method for creating document and folders in alfresco using CMIS.
Folder.createFolder(
Map<string, ?> properties,
List<Policy> policies, List<Ace> addAce, List<Ace> removeAce,
OperationContext context);
And I used Folder.createDocument for creating document (they have the same parameter) and used it as follow:
AlfrescoFolder.java
parentFolder.createFolder(
AlfrescoUtilities.mapAlfrescoObjectProperties("cmis:folder",
folderName, title, description, tags),
null, null, null,
AlfrescoSession.getSession().getDefaultContext()
);
// AlfrescoSession.getSession() a custom method that we created to
// create a Session variable
AlfrescoUtilities.java
public static Map<String, Object> mapAlfrescoObjectProperties(
String objectType, String name, String title, String description,
List<String> tags)
{
Map<String, Object> properties = new HashMap<>();
properties.put(PropertyIds.OBJECT_TYPE_ID,
objectType + ",P:cm:titled,P:cm:taggable");
properties.put(PropertyIds.NAME, name);
if (title != null) properties.put("cm:title", title);
if (description != null) properties.put("cm:description", description);
if (tags != null) properties.put("cm:taggable", tags);
return properties;
}
}
In the code above, the objectType parameter there will be either cmis:folder or cmis:document and we discovered that to add aspects for adding description is to add P:cm:titled to add description and title and P:cm:taggable to attach tags.
Now, I'm working on a .NET application using C#.
When I translated it and used the same methods, the only problem is it is only working when I removed the P:cm:tittled; P:cm:taggable
Here is the current code for creating the properties:
AlfrescoUtilities.cs
public static Dictionary<string, object> mapAlfrescoObjectProperties(
string objectType, string name, string title, string description,
List<string> tags)
{
Dictionary<string, object> properties = new Dictionary<string, object>();
properties[PropertyIds.ObjectTypeId] = objectType;
// +",P:cm:titled,P:cm:taggable";
properties[PropertyIds.Name] = name; /*
if (title != null) properties["cm:title"] = title;
if (description != null) properties["cm:description"] = description;
if (tags != null) properties["cm:taggable"] = tags;
*/
return properties;
}
And as you noticed, I commented the other codes.
The only once that work is the objecttypeid (whether cmis:folder or cmis:document)
and the name.
Kindly help me regarding this. This is a windows application using .NET 3.5 and C#. Alfresco Version is 4.2.3
We verified that dotCmis <= 0.6.0 does not support CMIS 1.1 (and thus has no native support for aspect properties).
However, we successfully tested the approach described in
http://mail-archives.apache.org/mod_mbox/chemistry-dev/201202.mbox/%3C2D9094AD2E4FBE4B86B8B274D9DB9E081F7A754BF1#SSWPROD1001.synapps-solutions.com%3E
to work with the low-level CMIS API and manually take advantage of Alfresco CMIS extensions.
We also verified that in session.Query("select * from nm:aspectName ") result do contain the aspect properties.
Related
I am struggling to find the data type of AD attributes that are not having a value already.
Thus far a resulting DirecoryEntry only contains a property for attributes that already have a value. I can't find a method to obtain information about all other attributes.
Adding a value to the 'PropertiesToLoad' doesn't seem to do anything. The returned DirectoryEntry object contains all attributes (with values) regardless of what is added here.
Code used:
public void Test(string ldapPath)
{
Type orgType;
try
{
using (DirectoryEntry searchRoot = GetSearchRoot(ldapPath))
{
using (DirectorySearcher search = new DirectorySearcher(searchRoot))
{
search.Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=coen))";
search.PropertiesToLoad.Add("msExchHomeServerName");
SearchResult searchResult = search.FindOne();
{
using (DirectoryEntry entry = searchResult.GetDirectoryEntry())
{
if (entry != null)
{
if (entry.Properties.Contains("msExchHomeServerName"))
{
orgType = entry.Properties["msExchHomeServerName"].GetType();
}
else // The value is empty and NOT present in the current 'entry.Properties' object.
{
throw new Exception("Unknown type");
}
}
}
}
}
}
}
catch (Exception e)
{
<handle exception>
}
}
Is there a way to find the data type of the 'msExchHomeServerName' (or any of the 'empty' attributes) attribute?
Any help would be highly appreciated!
Coen
Active Directory has a schema. Obvious to say, not obvious to think about since, by default, you cannot explore it.
However, you can Register the Active Directory Schema MMC Snap-In1 and then, in a fresh instance of MMC, add that Snap-In.
This then allows you to explore the Classes and Attributes that make up your current AD schema (and add new classes/attributes if you know what you're doing and choose to do so).
msExchHomeServerName can then be discovered to be a "Unicode String", which means a plain string from C# should be acceptable. Note also that some types (particularly numeric ones) may also specify Minimums and Maximums which should be observed.
You can also explore the schema programatically via the ActiveDirectorySchema class, by e.g. calling ActiveDirectorySchema.GetCurrentSchema(); and then explore from there.
1I cannot remember if you need to have installed the general Domain Admin tools (such as Users and Computers) in order for that DLL to exist on your system.
Thanks to Damien_The_Unbeliever who pointed me in the right direction, I managed to create the following method:
public Dictionary<string, ActiveDirectorySyntax> GetAttributeSyntaxes(List<string> lstAttributeNames)
{
Dictionary<string, ActiveDirectorySyntax> dictRes = new Dictionary<string, ActiveDirectorySyntax>();
if (lstAttributeNames.Count > 0)
{
DirectoryContext directoryContext = new DirectoryContext(DirectoryContextType.DirectoryServer,
m_Server, m_UserName, m_Password);
using (ActiveDirectorySchema currentSchema = ActiveDirectorySchema.GetSchema(directoryContext))
{
using (ActiveDirectorySchemaClass objClass = currentSchema.FindClass("user"))
{
if (objClass != null)
{
ReadOnlyActiveDirectorySchemaPropertyCollection propcol = objClass.GetAllProperties();
foreach (ActiveDirectorySchemaProperty schemaProperty in propcol)
{
foreach (string attrName in lstAttributeNames)
{
if (schemaProperty.Name.Equals(attrName))
{
dictRes.Add(attrName, schemaProperty.Syntax);
break;
}
}
}
}
}
}
}
return dictRes;
}
The returned 'schemaProperty.Syntax' contains sufficient information to determine the actual data type.
Thanks Damien!
I'm working with MFiles API...
I want to pass a propertyDef to a propertyValue...
This code is working... but I have to create the MFiles object first.
ObjectVersionAndProperties objVersion =
mFilesStructure.MFileVault.ObjectOperations.CreateNewObject(objTypeID,
propValues);
var testPropValues = new PropertyValues();
testPropValues = FilesStructure.MFileVault.ObjectPropertyOperations.GetProperties(objVersion.ObjVer);
var testPropValue = new PropertyValue();
testPropValue = testPropValues.SearchForProperty(typeClientID);
it work fine "testPropValue" has all the property set correctly espacially the DataType... but don't want to create the MFiles at first...
This should do the same, in my opinion but doesn't
var test = new PropertyDef();
test = mFilesStructure.MFileVault.PropertyDefOperations.GetPropertyDef(typeClientID);
var testPropValue = new PropertyValue();
testPropValue.PropertyDef = test.ID;
the properties doesn't setup correctly...
Any one can help
Best regards,
Steph
I just stumbled across this looking for something else and thought I might help.
You actually have it a little backwards. The creation of the new object is actually the last step in the process. You need to create a collection of PropertyValues() by creating each individual PropertyValue() and then adding them to the collection.
So something like this:
public static PropertyValue GetPropertyValue(int propertyDefId, object value)
{
//resolve property def by ID
PropertyDef propertyDef = Vault.PropertyDefOperations.GetPropertyDef(propertyDefId);
//create the property value with prop def ID and value
return GetPropertyValue(propertyDefId, propertyDef.DataType, value);
}
public static PropertyValue GetPropertyValue(int propertyDefId, MFDataType dataType, object value)
{
PropertyValue propertyValue = new PropertyValue();
propertyValue.PropertyDef = propertyDefId;
propertyValue.TypedValue.SetValue(dataType, value);
return propertyValue;
}
public static ObjectVersionAndProperties CreateDocument(PropertyValues propertyValues, string filepath, Vault vault)
{
// Create the Source File object from the filepath.
SourceObjectFile sourceFile = new SourceObjectFile();
sourceFile.SourceFilePath = filepath;
sourceFile.Extension = Path.GetExtension(filepath).TrimStart('.');
sourceFile.Title = Path.GetFileNameWithoutExtension(filepath).TrimEnd('.');
// Create the document object.
return vault.ObjectOperations.CreateNewSFDObject((int)MFBuiltInObjectType.MFBuiltInObjectTypeDocument,
propertyValues, sourceFile, true);
}
Once you set up the above functions you could call them like:
//If the document doesn't exist, go ahead and create a new one
//creat and add all the properties
PropertyValues props = new PropertyValues();
//class
props.Add(-1, HelperMF.GetClassPropertyValue(classId, env.Vault));
//job
int jobId = env.Vault.ValueListItemOperations.GetValueListItemByDisplayID(Structure.ObjType.Job.ID, jobDisplayId).ID;
props.Add(-1, HelperMF.GetPropertyValue(Properties.Job.ID, jobId, env.Vault));
//estimates
props.Add(-1, HelperMF.GetPropertyValueFromListOfDisplayIds(env.Vault, Properties.Estimate.ID,
MFDataType.MFDatatypeMultiSelectLookup, Structure.ObjType.Estimate.ID, estimateDisplayIds));
//Add the relationship to the return doc that was uploaded
props.Add(-1, HelperMF.GetPropertyValue(Properties.Document.ID, movingDocId, env.Vault));
//create the new object in the vault
ObjectVersionAndProperties newDoc = HelperMF.CreateDocument(props, docDownloadPath, env.Vault);
I use a lot of help functions and classes but you should get the gist from my samples. Also, I would highly recommend you use the M-Files community website for research as they have a lot of code samples there geared specifically for M-Files.
https://community.m-files.com/
Also, if you don't already, use the API documentation as it also includes code samples.
http://www.m-files.com/api/documentation/2015.2/
Hopefully this helps,
Mike
All, a while back (when I was rushed off my feet) I asked the following question Performace Overheads when Using Resource Files (.resx) regarding the performance overhead of using resource strings. I got an up-voted answer and took the answer to be correct. However, before, I was localising message strings which are called in error conditions and not performance critical - now I have been asked to implement localisation to our codes 'power-house' (lots of performance critical code, embedded loops etc.).
Having some time to look into this in more detail and I noticed that calling a resource like
Resources.MessageStrings.SomeResourceName
merely refers the call to the auto-generated code MessageStrings.Designer.cs, which uses
internal static string SomeResourceName {
get {
return ResourceManager.GetString("SomeResourceName", resourceCulture);}
}
So digging deeper, I thought I would decompile ResourceManager which is found in
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5\mscorlib.dll
To see what GetString() was doing [Is it really caching my resource strings?]. Decompiling, I find
[__DynamicallyInvokable]
public virtual string GetString(string name, CultureInfo culture)
{
if (name == null)
throw new ArgumentNullException("name");
if (ResourceManager.s_IsAppXModel && object.ReferenceEquals((object) culture, (object) CultureInfo.CurrentUICulture))
culture = (CultureInfo) null;
if (this._bUsingModernResourceManagement)
{
if (this._PRIonAppXInitialized)
return this.GetStringFromPRI(name, culture == null ? (string) null : culture.Name, this._neutralResourcesCulture.Name);
if (this._PRIExceptionInfo == null || this._PRIExceptionInfo._PackageSimpleName == null || this._PRIExceptionInfo._ResWFile == null)
throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoPRIresources"));
throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_ResWFileNotLoaded", (object) this._PRIExceptionInfo._ResWFile, (object) this._PRIExceptionInfo._PackageSimpleName));
}
else
{
if (culture == null)
culture = Thread.CurrentThread.GetCurrentUICultureNoAppX();
if (FrameworkEventSource.IsInitialized)
FrameworkEventSource.Log.ResourceManagerLookupStarted(this.BaseNameField, this.MainAssembly, culture.Name);
ResourceSet resourceSet1 = this.GetFirstResourceSet(culture);
if (resourceSet1 != null)
{
string #string = resourceSet1.GetString(name, this._ignoreCase);
if (#string != null)
return #string;
}
foreach (CultureInfo culture1 in new ResourceFallbackManager(culture, this._neutralResourcesCulture, true))
{
ResourceSet resourceSet2 = this.InternalGetResourceSet(culture1, true, true);
if (resourceSet2 != null)
{
if (resourceSet2 != resourceSet1)
{
string #string = resourceSet2.GetString(name, this._ignoreCase);
if (#string != null)
{
if (this._lastUsedResourceCache != null)
{
lock (this._lastUsedResourceCache)
{
this._lastUsedResourceCache.lastCultureName = culture1.Name;
this._lastUsedResourceCache.lastResourceSet = resourceSet2;
}
}
return #string;
}
else
resourceSet1 = resourceSet2;
}
}
else
break;
}
if (FrameworkEventSource.IsInitialized)
FrameworkEventSource.Log.ResourceManagerLookupFailed(this.BaseNameField, this.MainAssembly, culture.Name);
return (string) null;
}
}
Nothing in the above code suggests that it is 'caching' my strings (in the typical/truest sense of the word), it seems it is doing a complex look-up of some type. I noticed that the method was using the undocumented __DynamicallyInvokable attribute, and found a breaf discussion of this attribute by Hans (What is the __DynamicallyInvokable attribute for?).
My question is: For performance critical code can I rely on the ResourceManager being fast enough (does it cache my strings?), or do I need to pre-process and cache the resource strings myself?
Thanks for your time.
The ressources are cached. If you follow the call stack through the resource manager it is like this:
1.
[System.Security.SecuritySafeCritical] // auto-generated
public virtual String GetString(String name, CultureInfo culture) {
//...
String value = rs.GetString(name, _ignoreCase);
//...
}
2.
public virtual string GetString(string name, bool ignoreCase)
{
object objectInternal = this.GetObjectInternal(name);
//...
}
3.
private object GetObjectInternal(string name)
{
//...
Hashtable hashtable = this.Table;
//...
return hashtable[(object) name];
}
So at this point the values is read from the hashtable.
The hashtable is filled once the ressource file is accessed:
Constructor:
[SecuritySafeCritical]
public ResourceSet(string fileName)
{
this.Reader = (IResourceReader) new ResourceReader(fileName);
this.CommonInit();
this.ReadResources();
}
and the ReadResources:
protected virtual void ReadResources()
{
IDictionaryEnumerator enumerator = this.Reader.GetEnumerator();
while (enumerator.MoveNext())
{
object obj = enumerator.Value;
this.Table.Add(enumerator.Key, obj);
}
}
The things that are being held in memory are things like the ResourceSets that it's working with, and those seem to directly hold the strings. You don't necessarily see it inside this method because at this point, every call could be coming in for different resource names and different cultures.
And, as always, is this where your profiling has told you that you have a performance issue? It's rarely, if ever, a good idea to try to optimize code by guessing at places that might be inefficient.
Is it possible to read the publisher name of the currently running ClickOnce application (the one you set at Project Properties -> Publish -> Options -> Publisher name in Visual Studio)?
The reason why I need it is to run another instance of the currently running application as described in this article and pass parameters to it.
Of course I do know my application's publisher name, but if I hard code it and later on I decide to change my publisher's name I will most likely forget to update this piece of code.
Here is another option. Note that it will only get the publisher name for the currently running application, which is all I need.
I'm not sure if this is the safest way to parse the XML.
public static string GetPublisher()
{
XDocument xDocument;
using (MemoryStream memoryStream = new MemoryStream(AppDomain.CurrentDomain.ActivationContext.DeploymentManifestBytes))
using (XmlTextReader xmlTextReader = new XmlTextReader(memoryStream))
{
xDocument = XDocument.Load(xmlTextReader);
}
var description = xDocument.Root.Elements().Where(e => e.Name.LocalName == "description").First();
var publisher = description.Attributes().Where(a => a.Name.LocalName == "publisher").First();
return publisher.Value;
}
You would think this would be trivial, but I don't see anything in the framework that gives you this info.
If you want a hack, you can get the publisher from the registry.
Disclaimer - Code is ugly and untested...
...
var publisher = GetPublisher("My App Name");
...
public static string GetPublisher(string application)
{
using (var key = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Uninstall"))
{
var appKey = key.GetSubKeyNames().FirstOrDefault(x => GetValue(key, x, "DisplayName") == application);
if (appKey == null) { return null; }
return GetValue(key, appKey, "Publisher");
}
}
private static string GetValue(RegistryKey key, string app, string value)
{
using (var subKey = key.OpenSubKey(app))
{
if (!subKey.GetValueNames().Contains(value)) { return null; }
return subKey.GetValue(value).ToString();
}
}
If you find a better solution, please follow-up.
I dont know about ClickOnce, but normally, you can read the assembly-info using the System.Reflection framework:
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
Unfortunately, theres no "publisher" custom-attribute, just throwing this out as a possible work-around
I am building an online store for local artists, and one of the requirements is to add an image to be associated with a given product. For the image, there are multiple elements that need to be validated; specifically dimensions, file size, and type.
Currently, I have the following set up to validate the image:
[LocalizedDisplayName(typeof(StoreManagementRes), "Image")]
[ImageSize(typeof(BesLogicSharedRes),"ValidationImageFileSizeMustBeLessThan20kb")]
[ImageDimension(typeof(BesLogicSharedRes), "ValidationImageDimensionMustBeLessThan640x480")]
[ImageType(typeof(BesLogicSharedRes), "ValidationImageTypeMustBeJpgOrPng")]
public int ImageFileId { get; set; }
The file that is uploaded does get validated properly, however, they are not necessarily called in the same order every time the application runs. In the end, if validation fails on more than one attribute, only one error message gets displayed. Again, not necessarily the first failed validation, nor the last. I would like to display all the errors at once so as not to frustrate the user.
If this is relevant, all three image validation classes are sub classed from ValidationAttribute.
One thing to be thankful of is that the model keeps all errors rather than one of them, it's just the HtmlHelper that's displaying the first.
ValidationSummary should in fact display all errors on your model though I suspect you want the equivalent for an individual property.
Unfortunately a couple of the useful methods are private rather than protected so they had to be copy and pasted out of ValidationExtensions.cs. I did this with a slightly cut down version (no use of resource files for error messages, easy enough to do by getting the original version of GetUserErrorMessageOrDefault but you'll also have to check to take the related methods and fields from the class too). I also only did one function call but it's easy enough to impliment the overloads if needed.
public static MvcHtmlString ValidationSummaryForSubModel(this HtmlHelper html, bool excludePropertyErrors, string message, IDictionary<string, object> htmlAttributes)
{
string prefix = html.ViewData.TemplateInfo.HtmlFieldPrefix;
var props = html.ViewData.ModelState.Where(x => x.Key.StartsWith(prefix));
var errorprops = props.Where(x => x.Value.Errors.Any()).SelectMany(x=>x.Value.Errors);
if (html == null) {
throw new ArgumentNullException("html");
}
FormContext formContext = (html.ViewContext.ClientValidationEnabled) ? html.ViewContext.FormContext : null;
if (formContext == null && html.ValidForSubModel())
{
return null;
}
string messageSpan;
if (!String.IsNullOrEmpty(message)) {
TagBuilder spanTag = new TagBuilder("span");
spanTag.SetInnerText(message);
messageSpan = spanTag.ToString(TagRenderMode.Normal) + Environment.NewLine;
}
else {
messageSpan = null;
}
StringBuilder htmlSummary = new StringBuilder();
TagBuilder unorderedList = new TagBuilder("ul");
foreach (ModelError modelError in errorprops) {
string errorText = GetUserErrorMessageOrDefault(html.ViewContext.HttpContext, modelError, null /* modelState */);
if (!String.IsNullOrEmpty(errorText)) {
TagBuilder listItem = new TagBuilder("li");
listItem.SetInnerText(errorText);
htmlSummary.AppendLine(listItem.ToString(TagRenderMode.Normal));
}
}
if (htmlSummary.Length == 0) {
htmlSummary.AppendLine(_hiddenListItem);
}
unorderedList.InnerHtml = htmlSummary.ToString();
TagBuilder divBuilder = new TagBuilder("div");
divBuilder.MergeAttributes(htmlAttributes);
divBuilder.AddCssClass((html.ViewData.ModelState.IsValid) ? HtmlHelper.ValidationSummaryValidCssClassName : HtmlHelper.ValidationSummaryCssClassName);
divBuilder.InnerHtml = messageSpan + unorderedList.ToString(TagRenderMode.Normal);
if (formContext != null) {
// client val summaries need an ID
divBuilder.GenerateId("validationSummary");
formContext.ValidationSummaryId = divBuilder.Attributes["id"];
formContext.ReplaceValidationSummary = !excludePropertyErrors;
}
return MvcHtmlString.Create(divBuilder.ToString(TagRenderMode.Normal));
}
private static string GetUserErrorMessageOrDefault(HttpContextBase httpContext, ModelError error, ModelState modelState)
{
if (!String.IsNullOrEmpty(error.ErrorMessage))
{
return error.ErrorMessage;
}
if (modelState == null)
{
return null;
}
string attemptedValue = (modelState.Value != null) ? modelState.Value.AttemptedValue : null;
//return String.Format(CultureInfo.CurrentCulture, GetInvalidPropertyValueResource(httpContext), attemptedValue);
return "Error";
}