ActivityLibrary for Sharepoint Designer - c#

I'm trying to implement an MSDN tutorial to create an activity library for Sharepoint Designer, and it gives me this error:
Namespace1.CreateTaskInListOnSite' does not contain a definition for 'ListName' and no extension method 'ListName' accepting a ...
and the same for AssignedTo and 'SiteUrl`.
Shouldn't 'AssignedTo', 'ListName' and 'SiteUrl' be inherited members from SequenceActivity class?
Here is the code which is erred:
protected override ActivityExecutionStatus
Execute(ActivityExecutionContext executionContext)
{
try
{
SPSite sitecollection = new SPSite(this.SiteUrl); //here
SPWeb web = sitecollection.OpenWeb();
SPUser user = web.Users[this.AssignTo[0].ToString()]; // here
SPList list = web.Lists[this.ListName]; // and here
SPListItem item = list.Items.Add();
item["Title"] = this.TaskTitle;
item["AssignedTo"] = user;
item.Update();
}
catch (Exception ex)
{
EventLog.WriteEntry("MSDN Workflow", ex.ToString());
}
return ActivityExecutionStatus.Closed;
}
Here is the .actions file:
<?xml version="1.0" encoding="utf-8" ?>
<WorkflowInfo>
<Actions Sequential="then" Parallel="and">
<Action Name="Create Task in List On Site"
ClassName="Namespace1.CreateTaskInListOnSite"
Assembly="CustomWorkflowActivities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a3170baa21b0a3e9"
AppliesTo="all" Category="Cross Site Actions">
<RuleDesigner
Sentence="Create task titled %1 for %2 on site %3 in
list %4">
<FieldBind Field="TaskTitle" DesignerType="TextArea"
Id="1"/>
<FieldBind Field="AssignTo" DesignerType="Person"
Text="this user" Id="2"/>
<FieldBind Field="SiteUrl" DesignerType="TextArea" Id="3"/>
<FieldBind Field="ListName" DesignerType="TextArea" Id="4"/>
</RuleDesigner>
<Parameters>
<Parameter Name="TaskTitle" Type="System.String, mscorlib"
Direction="In" />
<Parameter Name="AssignTo" Type="System.String, mscorlib"
Direction="In" />
<Parameter Name="SiteUrl" Type="System.String, mscorlib"
Direction="In" />
<Parameter Name="ListName" Type="System.String, mscorlib"
Direction="In" />
</Parameters>
</Action>

The .ACTIONS file calls the ClassName as MSDN.HowTo.CreateTaskInListOnSite, where as in your code file you seem to use the namespace Namespace1. The two have to match.
So either you change .ACTIONS to this:
<Action Name="Create Task in List On Site"
ClassName="MSDN.HowTo.CreateTaskInListOnSite" .... />
or change the namespace definition in your code file to MSDN.HowTo.
The assembly attribute values also have to be correct. You can use the sn.exe tool to retrieve the public key token for your assembly.

Related

AspNet Core 5.0 and register custom NLog LayoutRenderer

I use NLog.Web.AspNetCore 4.10.0 in my ASP Net Core 5.0 application. And I created a simple custom ResultLayoutRenderer (shortened for simplicity):
[LayoutRenderer("result-payload")]
public class ResultLayoutRenderer : AspNetLayoutRendererBase
{
protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
var httpRequest = HttpContextAccessor?.HttpContext?.Request;
var result = httpRequest.Headers["Result"];
builder.Append(result);
}
}
My NLog config is the following:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<!-- enable asp.net core layout renderers -->
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target xsi:type="Null" name="blackhole" />
<target name="database" xsi:type="Database"
dbProvider="Npgsql.NpgsqlConnection, Npgsql"
dbHost="${configsetting:name=NlogConnection.DbHost}"
dbDatabase="${configsetting:name=NlogConnection.Database}"
dbUserName="${configsetting:name=NlogConnection.User}"
dbPassword="${configsetting:name=NlogConnection.Password}"">
<commandText>
INSERT INTO logs (Application, Logged, Level, Message, Logger, Result)
VALUES (#Application, #Logged, #Level, #Message, #Logger, #Result);
</commandText>
<parameter name="#application" layout="AspNetCoreNlog" />
<parameter name="#logged" layout="${date}" />
<parameter name="#level" layout="${level}" />
<parameter name="#message" layout="${message}" />
<parameter name="#logger" layout="${logger}" />
<parameter name="#result" layout="${result-payload}" />
</target>
</targets>
</nlog>
I register the ResultLayoutRenderer in the Programm.cs:
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config")
.Setup()
.SetupExtensions(s => s.RegisterLayoutRenderer<InputDataLayout>("result-payload"))
.GetCurrentClassLogger();
..............
}
But the layout doesn't work. The NLog internal log file contains the following information:
Error Error parsing layout input-payload will be ignored. Exception: System.ArgumentException: LayoutRenderer cannot be found: 'input-payload'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Layouts.LayoutParser.GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, String name, Nullable`1 throwConfigExceptions)
You are very close. NLogBuilder.ConfigureNLog(...) is soon obsolete, so instead try this:
var logger = NLog.LogFactory.Setup()
.SetupExtensions(s =>
s.AutoLoadAssemblies(false)
.RegisterNLogWeb()
.RegisterLayoutRenderer<ResultLayoutRenderer>("result-payload"))
)
.LoadConfigurationFromFile("nlog.config")
.GetCurrentClassLogger();
See also: https://github.com/NLog/NLog.Web/blob/master/examples/ASP.NET%20Core%205/ASP.NET%20Core%205%20NLog%20Example/Program.cs
This works in my ASP.NET Core 5 Web API:
public static void Main(string[] args)
{
LayoutRenderer.Register<ElapsedTimeLayoutRenderer>("elapsed-time");
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
// ...
}
https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-5
https://www.carlosjanderson.com/log-the-elapsed-time-between-log-entries-using-nlog/

How can I get custom action data of a setup project in C#?

I create a windows service and a setup project for my service.
In my windows service I can get my customer action data thinks to this :
Context.Parameters["dbname"]
But I want to access to the value of my customer action data in my service to use it in my project.
Someone have any idea how to do it in c# ?
UPDATE
In my ProjectInstaller :
public ProjectInstaller()
{
InitializeComponent();
}
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
string dbName = Context.Parameters["dbname"];
AppHelper.Save(dbName+" "+ Context.Parameters["targetdir"].ToString());
string xml = Context.Parameters["targetdir"].ToString() + "App.config";
XmlDocument document = new XmlDocument();
document.Load(xml);
XPathNavigator navigator = document.CreateNavigator();
XmlNamespaceManager ns = new XmlNamespaceManager(navigator.NameTable);
foreach (XPathNavigator nav in navigator.Select(#"/configuration.appSettings/add[#key='dbName']"))
{
nav.SetValue(dbName);
}
document.Save(xml);
}
the app.config of my windows service :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="dbName" value="totodb"/>
</appSettings>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v13.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
When I try to install my project I have an error which say that my app.config doesn't exist.
This is working for me. You will need to replace ConsoleApp2 with your output filename.
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
string dbName = Context.Parameters["dbname"].ToString();
string xml = Context.Parameters["name"].ToString() + "ConsoleApp2.exe.config";
XmlDocument document = new XmlDocument();
document.Load(xml);
XmlNode dbNameNode = document.SelectSingleNode("//configuration/appSettings/add[#key='dbName']");
dbNameNode.Attributes["value"].Value = dbName;
document.Save(xml);
}
and my custom action data is:
/name="[TARGETDIR]\" /dbname=[EDITA1]
You can add MessageBox and things in to aid debugging.

Unable to get NLog to send fields as numbers/ints/longs from code

Our tack is c# .net 4.7 logging through NLog library to a "Graylog" GELF input which of course is storing them in an elasticsearch cluster.
The application utilizes logging heavily, but EVERYTHING is sent through as strings - no matter if it was something other than a string in code.
I want to be able send my custom logger properties as their true data types so that I can aggregate on my statistical number fields.
I DO NOT want to constrain my developers and do this with scripted fields, or pre-mapping an index in elasticsearch - in fact, graylog manages my index for me. Nor do I want to utilize graylog pipeline processor - my poor graylog does enough work. I want them to be able to send stat data as their real data types and have them mapped as "long" or "number".
A code snippet from my stuff:
public void InfoExtended2(String Message, Dictionary<string, int> extrafields, [CallerMemberName] string callerMethodName = "", [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
var fileName = callerFilePath.Substring(callerFilePath.LastIndexOf(#"\") + 1).Replace(".cs", "");
var caller = $"{fileName}.{callerMethodName}()Line:{sourceLineNumber}";
var logger = LogManager.GetLogger(caller);
if (!(extrafields.Count == 0))
{
foreach (var field in extrafields)
{
string mykey = field.Key.ToString();
extrafields.TryGetValue(field.Key, out int myvalue);
//be careful whats in object!
if (!logger.Properties.ContainsKey(mykey)) { logger.Properties.Add(mykey, "{#myvalue}"); } else { logger.Properties[mykey] = "{#myvalue}"; }
}
}
logger.Info()
.Message(Message)
.Property("ComeOnNow3", 87)
.Write();
// Create the LogEventInfo object
//LogEventInfo logEvent = new LogEventInfo();
// Now add the event characteristics
//logEvent.Properties["EventCode"] = 2222;
//logEvent.Level = NLog.LogLevel.Info;
//logEvent.Properties["EventCode]."]
//logEvent.Message = "My Message";
////logEvent.Exception = ex;
//logger.Log(logEvent);
//logger.Info("{#Message}", new Dictionary<string, int> { { "key1", 1 }, { "key2", 2 } }); // dict. Result: Test "key1"=1, "key2"=2
}
I've tried a few different ways there with no luck.
If I make a POST GELF call myself with JSON fields representing ints instead of strings, it works. My field is brand new to the index and when I go check the mapping it comes back as a long. I want my code to do that.
Test GELF Call:
{
"version": "1.1",
"host": "example.org",
"short_message": "A short message that helps you identify what is going on",
"full_message": "Backtrace here\n\nmore stuff",
"timestamp": 1385053862.3072,
"level": 1,
"_user_id": 9001,
"_some_info": "foo",
"_some_env_var": "bar"
}
Resulting mapping for user id:
"user_id" : {
"type" : "long"
What our nlog target currently looks like:
<targets>
<target name="gelftcp"
type="gelftcp"
facility="Custom Facility"
remoteaddress="192.168.95.15"
remoteport="12201"
layout="${longdate}${newline}type: ${level:uppercase=true}${newline}class: ${logger}${newline}stacktrace: ${stacktrace}${newline}error message: ${message}${newline}exception: ${exception:format=tostring,data:maxinnerexceptionlevel=10}">
<parameter name="logged_at" layout="${longdate}" />
<parameter name="type" layout="${level:uppercase=true}" />
   <parameter name="class" layout="${logger}" />
<parameter name="CustomInt" layout="${event-properties:item=CustomInt}" as="number" />
   <parameter name="stacktrace" layout="${stacktrace}" />
   <parameter name="error_message" layout="${message}" />
<parameter name="ComeOnNow3" layout="${event-properties:item=ComeOnNow3} " />
   <parameter name="exception" layout="${exception:format=tostring,data:maxinnerexceptionlevel=10}" />
<attribute name="eventProperties" encode="false" >
<layout type='JsonLayout' includeAllProperties="true" maxRecursionLimit="2"/>
</attribute>
<variable name="ComeOnNow2" value ="${event-context:ComeOnNow2}" />
</target>
Take it easy on me, I'm not the original author of this code. Just someone tasked with picking up slack & deploying in its current state.
UPDATE:
Tried the first suggestion. Even added the field I'm testing:
<field name="ComeOnNow3" layout="${threadid}" type="System.Int32" />
Attempted this log entry:
logger.Info()
.Message(Message)
.Property("ComeOnNow3", 87)
.Write();
My mapping still comes back as "keyword".
SOLVED:
The trick was to switch to Http instead of Tcp.
Instead of using "gelftcp". Then you can try out GelfLayout instead:
https://www.nuget.org/packages/NLog.GelfLayout
You can combine it with the TCP network-target:
<nlog>
<extensions>
<add assembly="NLog.Layouts.GelfLayout" />
</extensions>
<targets async="true">
<target type="Network" name="gelftcp" address="tcp://192.168.95.15:12201" newLine="true" lineEnding="Null">
<layout type="GelfLayout" facility="MyFacility">
<field name="threadid" layout="${threadid}" type="System.Int32" />
</layout>
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="gelftcp" />
</rules>
</nlog>
It also has some automatic conversion logic for simple NLog LogEventInfo.Properties (Decimal + Double + Integer + Boolean)
More examples can be found here: https://github.com/farzadpanahi/NLog.GelfLayout

Showing PDF-File with MVVM Cross on Android and IOS

I want to open a PDF on the Phone via the File-Path but i cant figure out how i could do this properly without using 3rd party packages.
You have any suggestion for this?
I already tried to use this on Android:
public void OpenFile(string filePath)
{
var fileToOpen = new Java.IO.File(filePath);
var uri = FileProvider.GetUriForFile(Application.Context, Application.Context.PackageName + ".fileprovider", fileToOpen);
var intent = new Intent();
var mime = IOUtil.GetMimeType(uri.ToString());
intent.SetAction(Intent.ActionView);
intent.SetDataAndType(uri, mime);
intent.SetFlags(ActivityFlags.NewTask);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
Application.Context.StartActivity(intent);
}
But i get the following Error:
Unhandled Exception:
Java.Lang.NullPointerException: Attempt to invoke virtual method
'android.content.res.XmlResourceParser
android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager,
java.lang.String)' on a null object reference
first you should addd this code to your manifest file :
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.easyphotopicker.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths"
tools:replace="android:resource"/>
</provider>
and create filepaths :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path name="root" path="" /> //root directory of the device new File("/");
<files-path name="files" path="" /> //context.getFilesDir()
<cache-path name="cache" path="" /> //context.getCacheDir()
<external-path name="external" path="" /> //Environment.getExternalStorageDirectory()
<external-files-path name="name" path="path" /> //context.getExternalFilesDirs()
<external-cache-path name="name" path="path" /> //getExternalCacheDirs()
</paths>
Your error is telling us that there is no file at the location matching that's passed into the function. There's a few ways of doing this, one of them is as shown. After accepting permissions to access folders and files, this should be one of the simplest ways. You seem to be close:
public void OpenPdfFile(string filename)
{
var f = new Java.IO.File(filename);
if (f.Exists())
{
System.Diagnostics.Debug.WriteLine("File exists!");
try
{
var openFileIntent = new Intent(Intent.ActionView);
openFileIntent.SetDataAndType(Android.Net.Uri.FromFile(f), "application/pdf");
openFileIntent.SetFlags(ActivityFlags.NoHistory);
StartActivity(Intent.CreateChooser(openFileIntent, "Open pdf file"));
}
catch (ActivityNotFoundException)
{
//handle when no available apps
}
}
}
I haven't tested your work, but the first thing would be to see if you added this to the Manifest file
android:authorities="com.{package}.{name}.fileprovider"
since your code says Application.Context.PackageName + ".fileprovider"

SharePoint Workflow Activity doesn't appear in SP Designer. Deployment was successful

I developed a SP Workflow Activity for SP Designer. The deployment is successful. In the webconfig-file the authorizedType is correctly inserted:
<authorizedType Assembly="WorkflowActivity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c8e215f3e395427" Namespace="AdventureWorksWFs" TypeName="*" Authorized="True" />
Source code:
public static DependencyProperty TestProperty = DependencyProperty.Register("Test", typeof(string), typeof(TestSite));
[Description("Name of the new Site")]
[Category("Sites")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string Test
{
get
{
return ((string)(base.GetValue(TestSite.TestProperty)));
}
set
{
base.SetValue(TestSite.TestProperty, value);
}
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
using (SPSite siteCollection = new SPSite(Url))
{
using (SPWeb web = siteCollection.OpenWeb())
{
using (SPWeb testWeb = web.Webs.Add(Test))
{
testWeb.Description = "This is a test!";
testWeb.Title = Test;
}
}
}
return ActivityExecutionStatus.Closed;
}
This is the .actions file:
<WorkflowInfo>
<Actions Sequential="then" Parallel="and">
<Action Name="Create New Site" ClassName="TestActivity.TestSite"
Assembly="TestActivity, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=5c25d241f3e851927" AppliesTo="all"
Category="Sites">
<RuleDesigner Sentence="Create TestSite">
<FieldBind Field="Test" Text="test" DesignerType="TextBox" Id="1" />
</RuleDesigner>
<Parameters>
<Parameter Name="Test" Type="System.String, mscorlib" Direction="In" />
</Parameters>
</Action>
</Actions>
</WorkflowInfo>
Can anyone help?
Search the following reference:
• Open the configuration file of the WebApplication where you installed the package: C:\Inetpub\wwwroot\wss\VirtualDirectories[Port Web App]\web.config
• Review to appear in the appropriate place the following two configuration entries that should create the installation of the solution:
<SafeControl Assembly="TestActivity.TestSite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c25d241f3e851927" Namespace="TestActivity.TestSite" TypeName="*" Safe="True" SafeAgainstScript="False" />
<authorizedType Assembly="TestActivity.TestSite, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c25d241f3e851927" Namespace="TestActivity.TestSite" TypeName="*" Authorized="True" />
If you are not manually add them where appropriate.
Then verify that the file is TestActivity.TestSite.Actions into the appropriate directory:
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\1033\Workflow\

Categories

Resources