├── Assets
├── Logo.ai
├── Logo.png
└── Logo.svg
├── Sample
├── Sample.Test
│ ├── Assets
│ │ ├── StoreLogo.png
│ │ ├── SplashScreen.scale-200.png
│ │ ├── LockScreenLogo.scale-200.png
│ │ ├── Square44x44Logo.scale-200.png
│ │ ├── Wide310x150Logo.scale-200.png
│ │ ├── Square150x150Logo.scale-200.png
│ │ └── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── UnitTestApp.xaml
│ ├── project.json
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ └── UnitTestApp.rd.xml
│ ├── Package.appxmanifest
│ ├── UnitTest.cs
│ ├── UnitTestApp.xaml.cs
│ └── Sample.Test.csproj
├── Sample.Consumer
│ ├── Assets
│ │ ├── StoreLogo.png
│ │ ├── LockScreenLogo.scale-200.png
│ │ ├── SplashScreen.scale-200.png
│ │ ├── Square44x44Logo.scale-200.png
│ │ ├── Wide310x150Logo.scale-200.png
│ │ ├── Square150x150Logo.scale-200.png
│ │ └── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── App.xaml
│ ├── project.json
│ ├── DataTemplateSelector.cs
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ └── Default.rd.xml
│ ├── MainPage.xaml.cs
│ ├── Viewmodel.cs
│ ├── Package.appxmanifest
│ ├── MainPage.xaml
│ ├── App.xaml.cs
│ └── Sample.Consumer.csproj
├── Sample.Provider
│ ├── Assets
│ │ ├── StoreLogo.png
│ │ ├── LockScreenLogo.scale-200.png
│ │ ├── SplashScreen.scale-200.png
│ │ ├── Square44x44Logo.scale-200.png
│ │ ├── Wide310x150Logo.scale-200.png
│ │ ├── Square150x150Logo.scale-200.png
│ │ └── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── App.xaml
│ ├── project.json
│ ├── MainPage.xaml
│ ├── MainPage.xaml.cs
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ └── Default.rd.xml
│ ├── Package.appxmanifest
│ ├── App.xaml.cs
│ └── Sample.Provider.csproj
├── Sample.Component
│ ├── project.json
│ ├── AppendPluginOptions.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── AppendPlugin.cs
│ ├── ReversePluginOptions.cs
│ ├── ReversePluginIntern.cs
│ └── Sample.Component.csproj
└── Sample.Definition
│ ├── project.json
│ ├── Properties
│ ├── AssemblyInfo.cs
│ └── Sample.Definition.rd.xml
│ ├── StringPluginsWithOptions.cs
│ ├── Options.cs
│ └── Sample.Definition.csproj
├── AppPlugin
├── Exceptions
│ ├── PluginException.cs
│ └── ConnectionFailure.cs
├── project.json
├── IPlugin.cs
├── AppPlugin.nuspec
├── Helper.cs
├── Properties
│ ├── AssemblyInfo.cs
│ └── AppExtensionService.rd.xml
├── GlobalSuppressions.cs
├── AbstractPlugin.cs
├── AbstractPluginWithOptins.cs
├── AbstractBasePlugin.cs
├── AppPlugin.csproj
└── PluginList
│ ├── PluginList.cs
│ ├── PluginListWithOptions.cs
│ └── AbstractPluginList.cs
├── License.md
├── AppPlugin.sln
├── .gitattributes
├── .gitignore
└── README.md
/Assets/Logo.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Assets/Logo.ai
--------------------------------------------------------------------------------
/Assets/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Assets/Logo.png
--------------------------------------------------------------------------------
/Sample/Sample.Test/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Test/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Consumer/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Provider/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/Sample/Sample.Test/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Test/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Test/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Test/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Test/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Test/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Test/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Test/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Consumer/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Consumer/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Provider/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Provider/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Test/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Test/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Consumer/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Consumer/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Provider/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Provider/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Consumer/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Provider/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Sample/Sample.Test/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Test/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Consumer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LokiMidgard/AppPlugin/HEAD/Sample/Sample.Provider/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/AppPlugin/Exceptions/PluginException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace AppPlugin.Exceptions
4 | {
5 | internal class PluginException : Exception
6 | {
7 |
8 | internal PluginException(string message) : base(message)
9 | {
10 | }
11 |
12 | }
13 | }
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Sample/Sample.Provider/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Sample/Sample.Test/UnitTestApp.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Sample/Sample.Component/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2"
4 | },
5 | "frameworks": {
6 | "uap10.0": {}
7 | },
8 | "runtimes": {
9 | "win10-arm": {},
10 | "win10-arm-aot": {},
11 | "win10-x86": {},
12 | "win10-x86-aot": {},
13 | "win10-x64": {},
14 | "win10-x64-aot": {}
15 | }
16 | }
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2"
4 | },
5 | "frameworks": {
6 | "uap10.0": {}
7 | },
8 | "runtimes": {
9 | "win10-arm": {},
10 | "win10-arm-aot": {},
11 | "win10-x86": {},
12 | "win10-x86-aot": {},
13 | "win10-x64": {},
14 | "win10-x64-aot": {}
15 | }
16 | }
--------------------------------------------------------------------------------
/Sample/Sample.Definition/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2"
4 | },
5 | "frameworks": {
6 | "uap10.0": {}
7 | },
8 | "runtimes": {
9 | "win10-arm": {},
10 | "win10-arm-aot": {},
11 | "win10-x86": {},
12 | "win10-x86-aot": {},
13 | "win10-x64": {},
14 | "win10-x64-aot": {}
15 | }
16 | }
--------------------------------------------------------------------------------
/Sample/Sample.Provider/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2"
4 | },
5 | "frameworks": {
6 | "uap10.0": {}
7 | },
8 | "runtimes": {
9 | "win10-arm": {},
10 | "win10-arm-aot": {},
11 | "win10-x86": {},
12 | "win10-x86-aot": {},
13 | "win10-x64": {},
14 | "win10-x64-aot": {}
15 | }
16 | }
--------------------------------------------------------------------------------
/AppPlugin/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2",
4 | "Nito.AsyncEx": "3.0.1"
5 | },
6 | "frameworks": {
7 | "uap10.0": {}
8 | },
9 | "runtimes": {
10 | "win10-arm": {},
11 | "win10-arm-aot": {},
12 | "win10-x86": {},
13 | "win10-x86-aot": {},
14 | "win10-x64": {},
15 | "win10-x64-aot": {}
16 | }
17 | }
--------------------------------------------------------------------------------
/Sample/Sample.Test/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2",
4 | "MSTest.TestAdapter": "1.1.4-preview",
5 | "MSTest.TestFramework": "1.0.5-preview",
6 | "Nito.AsyncEx": "3.0.1"
7 | },
8 | "frameworks": {
9 | "uap10.0": {}
10 | },
11 | "runtimes": {
12 | "win10-arm": {},
13 | "win10-arm-aot": {},
14 | "win10-x86": {},
15 | "win10-x86-aot": {},
16 | "win10-x64": {},
17 | "win10-x64-aot": {}
18 | }
19 | }
--------------------------------------------------------------------------------
/Sample/Sample.Provider/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/AppPlugin/IPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace AppPlugin
9 | {
10 | public interface IPlugin
11 | {
12 | Task ExecuteAsync(TIn input, IProgress progress = null, CancellationToken cancelTokem = default(CancellationToken));
13 | }
14 |
15 | public interface IPlugin
16 | {
17 | Task ExecuteAsync(TIn input, TOption options, IProgress progress = null, CancellationToken cancelTokem = default(CancellationToken));
18 |
19 | Task PrototypeOptions { get; }
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/AppPlugin/AppPlugin.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | $author$
8 | $author$
9 | https://github.com/LokiMidgard/AppExtensionService/blob/master/License.md
10 | https://github.com/LokiMidgard/AppExtensionService
11 | https://github.com/LokiMidgard/AppExtensionService/blob/master/Assets/Logo.png
12 | false
13 | $description$
14 |
15 | - Fixed Bugs
16 | - Added Sample
17 | - [BEAKING CHANGE] Method Signatures Changed
18 |
19 | Copyright 2016
20 | UWP AppService AppExtension Plugin
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Sample/Sample.Provider/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices.WindowsRuntime;
6 | using Windows.Foundation;
7 | using Windows.Foundation.Collections;
8 | using Windows.UI.Xaml;
9 | using Windows.UI.Xaml.Controls;
10 | using Windows.UI.Xaml.Controls.Primitives;
11 | using Windows.UI.Xaml.Data;
12 | using Windows.UI.Xaml.Input;
13 | using Windows.UI.Xaml.Media;
14 | using Windows.UI.Xaml.Navigation;
15 |
16 | // Die Elementvorlage "Leere Seite" wird unter https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x407 dokumentiert.
17 |
18 | namespace Sample.Provider
19 | {
20 | ///
21 | /// Eine leere Seite, die eigenständig verwendet oder zu der innerhalb eines Rahmens navigiert werden kann.
22 | ///
23 | public sealed partial class MainPage : Page
24 | {
25 | public MainPage()
26 | {
27 | this.InitializeComponent();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Sample/Sample.Component/AppendPluginOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Sample.Definition;
3 |
4 | namespace Sample.Component
5 | {
6 | internal class AppendPluginOptions : Options
7 | {
8 | internal static readonly Guid ID = new Guid("{ED1E7DD5-7059-461D-9FEE-A5F0F6C7CE5A}");
9 | private readonly AbstractOption[] abstractOption;
10 |
11 | public AppendPluginOptions()
12 | {
13 | this.abstractOption = new AbstractOption[]
14 | {
15 | new StringOption("To Append", "Defines the String that will be Append.") { Value = "[Please Set a Value]" }
16 | };
17 | }
18 |
19 |
20 | public AppendPluginOptions(Options o)
21 | {
22 | if (o.OptionsIdentifier != ID)
23 | throw new ArgumentException();
24 | this.abstractOption = o.Settings;
25 | }
26 |
27 | public StringOption Appending => this[0] as StringOption;
28 |
29 | public override Guid OptionsIdentifier => ID;
30 |
31 | protected override AbstractOption[] GetSettings() => this.abstractOption;
32 | }
33 | }
--------------------------------------------------------------------------------
/License.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Patrick Kranz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/DataTemplateSelector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Windows.UI.Xaml;
7 | using Windows.UI.Xaml.Controls;
8 | using Windows.UI.Xaml.Data;
9 |
10 | namespace Sample.Consumer
11 | {
12 | class OptionsSelector : DataTemplateSelector
13 | {
14 | public DataTemplate StringOptionTemplate { get; set; }
15 | public DataTemplate IntOptionTemplate { get; set; }
16 |
17 | protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
18 | {
19 | return SelectTemplate(item);
20 | }
21 |
22 | protected override DataTemplate SelectTemplateCore(object item)
23 | {
24 | switch (item)
25 | {
26 | case Definition.IntOption io:
27 | return this.IntOptionTemplate;
28 | case Definition.StringOption so:
29 | return this.StringOptionTemplate;
30 | default:
31 | return base.SelectTemplateCore(item);
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Sample.Consumer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Sample.Consumer")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Sample.Provider")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Sample.Provider")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/Sample/Sample.Component/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Sample.Component")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Sample.Component")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/Sample/Sample.Definition/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Sample.Definition")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Sample.Definition")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/Sample/Sample.Test/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Sample.Test")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Sample.Test")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 | [assembly: AssemblyMetadata("TargetPlatform","UAP")]
17 |
18 | // Version information for an assembly consists of the following four values:
19 | //
20 | // Major Version
21 | // Minor Version
22 | // Build Number
23 | // Revision
24 | //
25 | // You can specify all the values or you can default the Build and Revision Numbers
26 | // by using the '*' as shown below:
27 | // [assembly: AssemblyVersion("1.0.*")]
28 | [assembly: AssemblyVersion("1.0.0.0")]
29 | [assembly: AssemblyFileVersion("1.0.0.0")]
30 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/Sample/Sample.Component/AppendPlugin.cs:
--------------------------------------------------------------------------------
1 | using Sample.Definition;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Windows.ApplicationModel.Background;
9 |
10 | namespace Sample.Component
11 | {
12 | public sealed class AppendPlugin : IBackgroundTask
13 | {
14 | private IBackgroundTask internalTask = new AppendIntern();
15 | public void Run(IBackgroundTaskInstance taskInstance)
16 | => this.internalTask.Run(taskInstance);
17 | }
18 |
19 | internal class AppendIntern : StringPluginsWithOptions
20 | {
21 |
22 | protected override Task ExecuteAsync(string input, Options options, IProgress progress, CancellationToken cancelToken)
23 | {
24 | var revereseOptions = new AppendPluginOptions(options);
25 |
26 | return Task.FromResult(input + revereseOptions.Appending.Value ?? "");
27 | }
28 |
29 |
30 | protected override Task GetOptions()
31 | => Task.FromResult(new AppendPluginOptions());
32 |
33 | protected override Guid GetOptionsGuid() => AppendPluginOptions.ID;
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Sample/Sample.Component/ReversePluginOptions.cs:
--------------------------------------------------------------------------------
1 | using Sample.Definition;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Sample.Component
10 | {
11 |
12 | class ReversePluginOptions : Options
13 | {
14 | public static readonly Guid ID = new Guid("AB577183-9A64-47E0-B4B6-E8B5D309F537");
15 |
16 | private readonly AbstractOption[] abstractOption;
17 |
18 | public ReversePluginOptions()
19 | {
20 | this.abstractOption = new AbstractOption[]
21 | {
22 | new IntOption("Delay", "Sets the delay for each reverse operation in ms.", 0, 1000) { Value = 200 }
23 | };
24 | }
25 |
26 |
27 | public ReversePluginOptions(Options o)
28 | {
29 | if (o.OptionsIdentifier != ID)
30 | throw new ArgumentException();
31 | this.abstractOption = o.Settings;
32 | }
33 |
34 | public IntOption Delay => this[0] as IntOption;
35 |
36 | public override Guid OptionsIdentifier => ID;
37 |
38 | protected override AbstractOption[] GetSettings() => this.abstractOption;
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/AppPlugin/Helper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml;
9 |
10 | namespace AppPlugin
11 | {
12 | internal static class Helper
13 | {
14 | internal static string Serilize(T output)
15 | {
16 | string outputString;
17 | var serelizerOut = new DataContractSerializer(typeof(T));
18 | using (var stringWriter = new StringWriter())
19 | {
20 | using (var xmlWriter = XmlWriter.Create(stringWriter))
21 | serelizerOut.WriteObject(xmlWriter, output);
22 | outputString = stringWriter.ToString();
23 | }
24 |
25 | return outputString;
26 | }
27 |
28 | internal static T DeSerilize(string inputString)
29 | {
30 | T input;
31 | var serelizerIn = new DataContractSerializer(typeof(T));
32 | using (var stringReader = new StringReader(inputString))
33 | using (var xmlReader = XmlReader.Create(stringReader))
34 | input = (T)serelizerIn.ReadObject(xmlReader);
35 | return input;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/AppPlugin/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("AppPlugin")]
9 | [assembly: AssemblyDescription("This project combines UWP AppServices with AppExtensions and DataContracts in order to realize a more Code orientated way to write extensions.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Patrick Kranz")]
12 | [assembly: AssemblyProduct("AppPlugin")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("0.5.*")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
30 |
--------------------------------------------------------------------------------
/Sample/Sample.Test/Properties/UnitTestApp.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Sample/Sample.Definition/StringPluginsWithOptions.cs:
--------------------------------------------------------------------------------
1 | using AppPlugin;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Threading;
8 |
9 | namespace Sample.Definition
10 | {
11 | public abstract class StringPluginsWithOptions : AbstractPlugin
12 | {
13 |
14 | public const String PLUGIN_NAME = "Sample.StringPluginsWithOptions";
15 |
16 | protected sealed override Task ExecuteAsync(string input, TransfareOptions options, IProgress progress, CancellationToken cancelToken)
17 | {
18 | if (options.OptionsIdentifyer != GetOptionsGuid())
19 | throw new ArgumentException("Option Not generated by this Plugin", nameof(options));
20 | return ExecuteAsync(input, options.Options, progress, cancelToken);
21 | }
22 |
23 | protected sealed override async Task GetDefaultOptionsAsync()
24 | => new TransfareOptions() { Options = await GetOptions() };
25 |
26 | protected abstract Task ExecuteAsync(string input, Options options, IProgress progress, CancellationToken cancelToken);
27 |
28 | protected abstract Task GetOptions();
29 | protected abstract Guid GetOptionsGuid();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sample/Sample.Component/ReversePluginIntern.cs:
--------------------------------------------------------------------------------
1 | using Sample.Definition;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Threading;
8 | using Windows.ApplicationModel.Background;
9 |
10 | namespace Sample.Component
11 | {
12 |
13 | public sealed class ReveresPlugin : IBackgroundTask
14 | {
15 | private IBackgroundTask internalTask = new ReversePluginIntern();
16 | public void Run(IBackgroundTaskInstance taskInstance)
17 | => this.internalTask.Run(taskInstance);
18 | }
19 |
20 | internal class ReversePluginIntern : StringPluginsWithOptions
21 | {
22 |
23 | protected override async Task ExecuteAsync(string input, Options options, IProgress progress, CancellationToken cancelToken)
24 | {
25 | var revereseOptions = new ReversePluginOptions(options);
26 | var b = new StringBuilder();
27 | for (int i = input.Length - 1; i >= 0; i--)
28 | {
29 | b.Append(input[i]);
30 | if (cancelToken.IsCancellationRequested)
31 | break;
32 | progress.Report(b.Length / (double)input.Length);
33 | await Task.Delay(revereseOptions.Delay.Value);
34 | }
35 | return b.ToString();
36 | }
37 |
38 |
39 | protected override Task GetOptions()
40 | => Task.FromResult(new ReversePluginOptions());
41 |
42 | protected override Guid GetOptionsGuid() => ReversePluginOptions.ID;
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/AppPlugin/Properties/AppExtensionService.rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Sample/Sample.Definition/Properties/Sample.Definition.rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices.WindowsRuntime;
6 | using Windows.Foundation;
7 | using Windows.Foundation.Collections;
8 | using Windows.UI.Xaml;
9 | using Windows.UI.Xaml.Controls;
10 | using Windows.UI.Xaml.Controls.Primitives;
11 | using Windows.UI.Xaml.Data;
12 | using Windows.UI.Xaml.Input;
13 | using Windows.UI.Xaml.Media;
14 | using Windows.UI.Xaml.Navigation;
15 | using Plugin = AppPlugin.PluginList.PluginList.PluginProvider;
16 |
17 | // Die Elementvorlage "Leere Seite" wird unter https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x407 dokumentiert.
18 |
19 | namespace Sample.Consumer
20 | {
21 | ///
22 | /// Eine leere Seite, die eigenständig verwendet oder zu der innerhalb eines Rahmens navigiert werden kann.
23 | ///
24 | public sealed partial class MainPage : Page
25 | {
26 | public MainPage()
27 | {
28 | this.InitializeComponent();
29 | }
30 |
31 | private async void Button_Click(object sender, RoutedEventArgs e)
32 | {
33 | this.Progress.IsActive = true;
34 | this.List.IsEnabled = false;
35 | try
36 | {
37 |
38 | var b = sender as Button;
39 | var p = b.DataContext as Plugin;
40 | var o = await p.PrototypeOptions;
41 | var erg = await p.ExecuteAsync(this.Input.Text ?? "", o);
42 | this.Output.Text = erg;
43 |
44 | }
45 | finally
46 | {
47 | this.List.IsEnabled = true;
48 |
49 | this.Progress.IsActive = false;
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Viewmodel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Collections.Specialized;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Windows.UI.Xaml;
9 | using Plugin = AppPlugin.PluginList.PluginList.PluginProvider;
10 |
11 | namespace Sample.Consumer
12 | {
13 | class Viewmodel : DependencyObject
14 | {
15 |
16 | public ObservableCollection Plugins { get; }
17 | = new ObservableCollection();
18 |
19 | public Viewmodel()
20 | {
21 | #pragma warning disable CS4014 // Da dieser Aufruf nicht abgewartet wird, wird die Ausführung der aktuellen Methode fortgesetzt, bevor der Aufruf abgeschlossen ist
22 | InitAsync();
23 | #pragma warning restore CS4014 // Da dieser Aufruf nicht abgewartet wird, wird die Ausführung der aktuellen Methode fortgesetzt, bevor der Aufruf abgeschlossen ist
24 | }
25 |
26 | private async Task InitAsync()
27 | {
28 | await Task.Delay(5000);
29 | var list = await Definition.StringPluginsWithOptions.ListAsync(Definition.StringPluginsWithOptions.PLUGIN_NAME);
30 |
31 | foreach (var item in list.Plugins)
32 | this.Plugins.Add(item);
33 |
34 | (list.Plugins as INotifyCollectionChanged).CollectionChanged += async (sender, e) =>
35 | {
36 | await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
37 | {
38 | if (e.NewItems != null)
39 | foreach (var item in e.NewItems.OfType())
40 | this.Plugins.Add(item);
41 | if (e.OldItems != null)
42 | foreach (var item in e.OldItems.OfType())
43 | this.Plugins.Remove(item);
44 | });
45 | };
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
16 |
17 |
18 | Sample.Consumer
19 | patri
20 | Assets\StoreLogo.png
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | Sample.StringPluginsWithOptions
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Sample/Sample.Test/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
14 |
15 |
16 | Sample.Test
17 | patri
18 | Assets\StoreLogo.png
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Sample.StringPluginsWithOptions
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/AppPlugin.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppPlugin", "AppPlugin\AppPlugin.csproj", "{D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RepoFiles", "RepoFiles", "{5F8A45D1-4CA5-433A-8CF5-3E9D17CB21F1}"
9 | ProjectSection(SolutionItems) = preProject
10 | License.md = License.md
11 | README.md = README.md
12 | EndProjectSection
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Debug|ARM = Debug|ARM
18 | Debug|x64 = Debug|x64
19 | Debug|x86 = Debug|x86
20 | Release|Any CPU = Release|Any CPU
21 | Release|ARM = Release|ARM
22 | Release|x64 = Release|x64
23 | Release|x86 = Release|x86
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|ARM.ActiveCfg = Debug|ARM
29 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|ARM.Build.0 = Debug|ARM
30 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|x64.ActiveCfg = Debug|x64
31 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|x64.Build.0 = Debug|x64
32 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|x86.ActiveCfg = Debug|x86
33 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Debug|x86.Build.0 = Debug|x86
34 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|ARM.ActiveCfg = Release|ARM
37 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|ARM.Build.0 = Release|ARM
38 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|x64.ActiveCfg = Release|x64
39 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|x64.Build.0 = Release|x64
40 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|x86.ActiveCfg = Release|x86
41 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}.Release|x86.Build.0 = Release|x86
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/Sample/Sample.Test/UnitTest.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using System.Linq;
5 | using Nito.AsyncEx;
6 | using System.Threading.Tasks;
7 | using Sample.Definition;
8 |
9 | namespace Sample.Test
10 | {
11 | [TestClass]
12 | public class UnitTest1
13 | {
14 | [TestMethod]
15 | public void TestReversePlugin()
16 | {
17 | AsyncContext.Run(async () =>
18 | {
19 | var list = await Definition.StringPluginsWithOptions.ListAsync(Definition.StringPluginsWithOptions.PLUGIN_NAME);
20 | // await Task.Delay(10000);
21 | var reversePlugin = list.Plugins.SingleOrDefault(x => x.Extension.DisplayName == "String Reverser");
22 | Assert.IsNotNull(reversePlugin, "No Plugin Found Be shure to deploy the Project Sample.Provider");
23 |
24 | var options = await reversePlugin.PrototypeOptions;
25 |
26 | Assert.IsNotNull(options);
27 |
28 | const string toReverse = "Test";
29 | var result = await reversePlugin.ExecuteAsync(toReverse, options);
30 | Assert.AreEqual(new String(toReverse.Reverse().ToArray()), result);
31 |
32 | });
33 | }
34 |
35 | [TestMethod]
36 | public void TestAppendPlugin()
37 | {
38 | AsyncContext.Run(async () =>
39 | {
40 | var list = await Definition.StringPluginsWithOptions.ListAsync(Definition.StringPluginsWithOptions.PLUGIN_NAME);
41 | //await Task.Delay(10000);
42 | var reversePlugin = list.Plugins.SingleOrDefault(x => x.Extension.DisplayName == "String Appender");
43 | Assert.IsNotNull(reversePlugin, "No Plugin Found Be shure to deploy the Project Sample.Provider");
44 |
45 | var options = await reversePlugin.PrototypeOptions;
46 |
47 | Assert.IsNotNull(options);
48 | Assert.AreEqual(1, options.Count);
49 | Assert.IsInstanceOfType(options[0], typeof(StringOption));
50 |
51 | var strOptions = options[0] as StringOption;
52 | const string toAppend = "Appending";
53 | strOptions.Value = toAppend;
54 |
55 | const string input = "Test";
56 | var result = await reversePlugin.ExecuteAsync(input, options);
57 | Assert.AreEqual(input + toAppend, result);
58 |
59 | });
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Assets/Logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
45 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/Sample/Sample.Provider/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 | Sample.Provider
11 | patri
12 | Assets\StoreLogo.png
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
40 |
41 | ReverseService
42 |
43 |
44 |
45 |
46 |
51 |
52 | AppendService
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/AppPlugin/Exceptions/ConnectionFailure.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Windows.ApplicationModel.AppService;
7 |
8 | namespace AppPlugin.Exceptions
9 | {
10 |
11 | public class ConnectionFailureException : Exception
12 | {
13 | private AppServiceConnectionStatus status;
14 | private AppServiceConnection connection;
15 |
16 | public AppServiceResponseStatus Status { get; }
17 |
18 | internal ConnectionFailureException(AppServiceResponseStatus status) : base(GenerateMessage(status))
19 | {
20 | this.Status = status;
21 | }
22 |
23 | internal ConnectionFailureException(AppServiceConnectionStatus status, AppServiceConnection connection) : base(GenerateMessage(status, connection))
24 | {
25 | this.status = status;
26 | this.connection = connection;
27 | }
28 |
29 | private static string GenerateMessage(AppServiceResponseStatus status)
30 | {
31 | switch (status)
32 | {
33 | case AppServiceResponseStatus.Success:
34 | throw new ArgumentException("Success sollte keine Exception auslösen.", nameof(status));
35 | case AppServiceResponseStatus.Failure:
36 | case AppServiceResponseStatus.ResourceLimitsExceeded:
37 | case AppServiceResponseStatus.Unknown:
38 | case AppServiceResponseStatus.RemoteSystemUnavailable:
39 | case AppServiceResponseStatus.MessageSizeTooLarge:
40 | return "";
41 | default:
42 | return "Unknown failure";
43 | }
44 |
45 | }
46 |
47 | private static string GenerateMessage(AppServiceConnectionStatus status, AppServiceConnection connection)
48 | {
49 | switch (status)
50 | {
51 | case AppServiceConnectionStatus.Success:
52 | throw new ArgumentException("Success sollte keine Exception auslösen.", nameof(status));
53 | case AppServiceConnectionStatus.AppNotInstalled:
54 | return "The app AppServicesProvider is not installed. Deploy AppServicesProvider to this device and try again.";
55 | case AppServiceConnectionStatus.AppUnavailable:
56 | return "The app AppServicesProvider is not available. This could be because it is currently being updated or was installed to a removable device that is no longer available.";
57 | case AppServiceConnectionStatus.AppServiceUnavailable:
58 | return string.Format("The app AppServicesProvider is installed but it does not provide the app service {0}.", connection.AppServiceName);
59 | case AppServiceConnectionStatus.Unknown:
60 | return "An unkown error occurred while we were trying to open an AppServiceConnection.";
61 | case AppServiceConnectionStatus.RemoteSystemUnavailable:
62 | return "The remote system is unavailable.";
63 | case AppServiceConnectionStatus.RemoteSystemNotSupportedByApp:
64 | return "The Remote System is not supported by the app.";
65 | case AppServiceConnectionStatus.NotAuthorized:
66 | return "You are not authorized.";
67 | default:
68 | return "Unknown failure";
69 | }
70 |
71 |
72 |
73 |
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/AppPlugin/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 |
2 | // This file is used by Code Analysis to maintain SuppressMessage
3 | // attributes that are applied to this project.
4 | // Project-level suppressions either have no target or are given
5 | // a specific target and scoped to a namespace, type, member, etc.
6 |
7 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.AbstractPluginList`2.Catalog_PackageUpdating(Windows.ApplicationModel.AppExtensions.AppExtensionCatalog,Windows.ApplicationModel.AppExtensions.AppExtensionPackageUpdatingEventArgs)")]
8 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.AbstractPluginList`2.Catalog_PackageUpdated(Windows.ApplicationModel.AppExtensions.AppExtensionCatalog,Windows.ApplicationModel.AppExtensions.AppExtensionPackageUpdatedEventArgs)")]
9 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.AbstractPluginList`2.Catalog_PackageInstalled(Windows.ApplicationModel.AppExtensions.AppExtensionCatalog,Windows.ApplicationModel.AppExtensions.AppExtensionPackageInstalledEventArgs)")]
10 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.AbstractPluginList`2.Catalog_PackageUninstalling(Windows.ApplicationModel.AppExtensions.AppExtensionCatalog,Windows.ApplicationModel.AppExtensions.AppExtensionPackageUninstallingEventArgs)")]
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.AbstractPluginList`2.Catalog_PackageStatusChanged(Windows.ApplicationModel.AppExtensions.AppExtensionCatalog,Windows.ApplicationModel.AppExtensions.AppExtensionPackageStatusChangedEventArgs)")]
12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.AbstractPluginList`2.PluginConnection.Canceld")]
13 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.AbstractPluginList`2.PluginConnection.Connection_RequestReceived(Windows.ApplicationModel.AppService.AppServiceConnection,Windows.ApplicationModel.AppService.AppServiceRequestReceivedEventArgs)")]
14 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.PluginList`3.PluginConnection.Canceld")]
15 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.PluginList`3.PluginConnection.Connection_RequestReceived(Windows.ApplicationModel.AppService.AppServiceConnection,Windows.ApplicationModel.AppService.AppServiceRequestReceivedEventArgs)")]
16 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.PluginList`4.PluginConnection.Canceld")]
17 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~M:AppPlugin.PluginList.PluginList`4.PluginConnection.Connection_RequestReceived(Windows.ApplicationModel.AppService.AppServiceConnection,Windows.ApplicationModel.AppService.AppServiceRequestReceivedEventArgs)")]
18 |
19 |
--------------------------------------------------------------------------------
/AppPlugin/AbstractPlugin.cs:
--------------------------------------------------------------------------------
1 | using AppPlugin.PluginList;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Runtime.Serialization;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Xml;
11 | using Windows.ApplicationModel.AppService;
12 | using Windows.ApplicationModel.Background;
13 | using Windows.Foundation.Collections;
14 |
15 | namespace AppPlugin
16 | {
17 | ///
18 | /// Abstract class that can be implemented to define a simple Plugin that provides one Function.
19 | ///
20 | /// The Type that will be passed to the funtion. (Must have a valid )
21 | /// The return type of the function. (Must have a valid )
22 | /// The type that will be used to report progress. (Must have a valid )
23 | public abstract class AbstractPlugin : AbstractBasePlugin
24 | {
25 | ///
26 | /// Instanziate the Plugin.
27 | ///
28 | ///
29 | /// Normaly an AppService uses its own process without UI. It also does not provide a SyncronisationContext. This results that async/await calls will run in the ThreadPool. This includes the Progress report. If the Plugin spans many Tasks, progress will be reported with higher latency.
30 | ///
31 | /// Discrips if the code should be called using a SyncronisationContext.
32 | public AbstractPlugin(bool useSyncronisationContext = true) : base(useSyncronisationContext)
33 | {
34 |
35 | }
36 |
37 | ///
38 | /// Returns an Object that Lists the Availaible Plugins.
39 | ///
40 | ///
41 | /// The length must be less or equal to 39, because of a limitation of the appmanifest.
42 | ///
43 | ///
44 | /// the length of is 40 or greater.
45 | ///
46 | /// The Plugin name defined in the appmanifest.
47 | /// The
48 | public static async Task> ListAsync(string pluginName)
49 | {
50 | var pluginList = new PluginList(pluginName);
51 | await pluginList.InitAsync();
52 | return pluginList;
53 | }
54 |
55 | ///
56 | /// Provides the Funktionality of this Plugin.
57 | ///
58 | /// The Input Parameter.
59 | /// The Progress that will report data to the Client.
60 | /// The cancel token.
61 | /// The result of the execution.
62 | protected abstract Task Execute(TIn input, IProgress progress, CancellationToken cancelToken);
63 |
64 |
65 | internal override async Task PerformStartAsync(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args, Guid? id, CancellationTokenSource cancellationTokenSource)
66 | {
67 | var inputString = args.Request.Message[START_KEY] as String;
68 |
69 | var input = Helper.DeSerilize(inputString);
70 |
71 | var progress = new Progress(async r =>
72 | {
73 | var data = Helper.Serilize(r);
74 | var dataSet = new ValueSet();
75 | dataSet.Add(PROGRESS_KEY, data);
76 | dataSet.Add(ID_KEY, id);
77 | await sender.SendMessageAsync(dataSet);
78 | });
79 |
80 | var output = await Execute(input, progress, cancellationTokenSource.Token);
81 | return output;
82 | }
83 |
84 |
85 |
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Sample/Sample.Test/UnitTestApp.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices.WindowsRuntime;
6 | using Windows.ApplicationModel;
7 | using Windows.ApplicationModel.Activation;
8 | using Windows.Foundation;
9 | using Windows.Foundation.Collections;
10 | using Windows.UI.Xaml;
11 | using Windows.UI.Xaml.Controls;
12 | using Windows.UI.Xaml.Controls.Primitives;
13 | using Windows.UI.Xaml.Data;
14 | using Windows.UI.Xaml.Input;
15 | using Windows.UI.Xaml.Media;
16 | using Windows.UI.Xaml.Navigation;
17 |
18 | namespace Sample.Test
19 | {
20 | ///
21 | /// Provides application-specific behavior to supplement the default Application class.
22 | ///
23 | sealed partial class App : Application
24 | {
25 | ///
26 | /// Initializes the singleton application object. This is the first line of authored code
27 | /// executed, and as such is the logical equivalent of main() or WinMain().
28 | ///
29 | public App()
30 | {
31 | this.InitializeComponent();
32 | this.Suspending += this.OnSuspending;
33 | }
34 |
35 | ///
36 | /// Invoked when the application is launched normally by the end user. Other entry points
37 | /// will be used such as when the application is launched to open a specific file.
38 | ///
39 | /// Details about the launch request and process.
40 | protected override void OnLaunched(LaunchActivatedEventArgs e)
41 | {
42 |
43 | #if DEBUG
44 | if (System.Diagnostics.Debugger.IsAttached)
45 | {
46 | this.DebugSettings.EnableFrameRateCounter = true;
47 | }
48 | #endif
49 |
50 | Frame rootFrame = Window.Current.Content as Frame;
51 |
52 | // Do not repeat app initialization when the Window already has content,
53 | // just ensure that the window is active
54 | if (rootFrame == null)
55 | {
56 | // Create a Frame to act as the navigation context and navigate to the first page
57 | rootFrame = new Frame();
58 |
59 | rootFrame.NavigationFailed += this.OnNavigationFailed;
60 |
61 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
62 | {
63 | //TODO: Load state from previously suspended application
64 | }
65 |
66 | // Place the frame in the current Window
67 | Window.Current.Content = rootFrame;
68 | }
69 |
70 | Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
71 |
72 | // Ensure the current window is active
73 | Window.Current.Activate();
74 |
75 | Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments);
76 | }
77 |
78 | ///
79 | /// Invoked when Navigation to a certain page fails
80 | ///
81 | /// The Frame which failed navigation
82 | /// Details about the navigation failure
83 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
84 | {
85 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
86 | }
87 |
88 | ///
89 | /// Invoked when application execution is being suspended. Application state is saved
90 | /// without knowing whether the application will be terminated or resumed with the contents
91 | /// of memory still intact.
92 | ///
93 | /// The source of the suspend request.
94 | /// Details about the suspend request.
95 | private void OnSuspending(object sender, SuspendingEventArgs e)
96 | {
97 | var deferral = e.SuspendingOperation.GetDeferral();
98 | //TODO: Save application state and stop any background activity
99 | deferral.Complete();
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/Sample/Sample.Consumer/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices.WindowsRuntime;
6 | using Windows.ApplicationModel;
7 | using Windows.ApplicationModel.Activation;
8 | using Windows.Foundation;
9 | using Windows.Foundation.Collections;
10 | using Windows.UI.Xaml;
11 | using Windows.UI.Xaml.Controls;
12 | using Windows.UI.Xaml.Controls.Primitives;
13 | using Windows.UI.Xaml.Data;
14 | using Windows.UI.Xaml.Input;
15 | using Windows.UI.Xaml.Media;
16 | using Windows.UI.Xaml.Navigation;
17 |
18 | namespace Sample.Consumer
19 | {
20 | ///
21 | /// Stellt das anwendungsspezifische Verhalten bereit, um die Standardanwendungsklasse zu ergänzen.
22 | ///
23 | sealed partial class App : Application
24 | {
25 | ///
26 | /// Initialisiert das Singletonanwendungsobjekt. Dies ist die erste Zeile von erstelltem Code
27 | /// und daher das logische Äquivalent von main() bzw. WinMain().
28 | ///
29 | public App()
30 | {
31 | this.InitializeComponent();
32 | this.Suspending += this.OnSuspending;
33 | }
34 |
35 | ///
36 | /// Wird aufgerufen, wenn die Anwendung durch den Endbenutzer normal gestartet wird. Weitere Einstiegspunkte
37 | /// werden z. B. verwendet, wenn die Anwendung gestartet wird, um eine bestimmte Datei zu öffnen.
38 | ///
39 | /// Details über Startanforderung und -prozess.
40 | protected override void OnLaunched(LaunchActivatedEventArgs e)
41 | {
42 | var rootFrame = Window.Current.Content as Frame;
43 |
44 | // App-Initialisierung nicht wiederholen, wenn das Fenster bereits Inhalte enthält.
45 | // Nur sicherstellen, dass das Fenster aktiv ist.
46 | if (rootFrame == null)
47 | {
48 | // Frame erstellen, der als Navigationskontext fungiert und zum Parameter der ersten Seite navigieren
49 | rootFrame = new Frame();
50 |
51 | rootFrame.NavigationFailed += this.OnNavigationFailed;
52 |
53 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
54 | {
55 | //TODO: Zustand von zuvor angehaltener Anwendung laden
56 | }
57 |
58 | // Den Frame im aktuellen Fenster platzieren
59 | Window.Current.Content = rootFrame;
60 | }
61 |
62 | if (e.PrelaunchActivated == false)
63 | {
64 | if (rootFrame.Content == null)
65 | {
66 | // Wenn der Navigationsstapel nicht wiederhergestellt wird, zur ersten Seite navigieren
67 | // und die neue Seite konfigurieren, indem die erforderlichen Informationen als Navigationsparameter
68 | // übergeben werden
69 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
70 | }
71 | // Sicherstellen, dass das aktuelle Fenster aktiv ist
72 | Window.Current.Activate();
73 | }
74 | }
75 |
76 | ///
77 | /// Wird aufgerufen, wenn die Navigation auf eine bestimmte Seite fehlschlägt
78 | ///
79 | /// Der Rahmen, bei dem die Navigation fehlgeschlagen ist
80 | /// Details über den Navigationsfehler
81 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
82 | {
83 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
84 | }
85 |
86 | ///
87 | /// Wird aufgerufen, wenn die Ausführung der Anwendung angehalten wird. Der Anwendungszustand wird gespeichert,
88 | /// ohne zu wissen, ob die Anwendung beendet oder fortgesetzt wird und die Speicherinhalte dabei
89 | /// unbeschädigt bleiben.
90 | ///
91 | /// Die Quelle der Anhalteanforderung.
92 | /// Details zur Anhalteanforderung.
93 | private void OnSuspending(object sender, SuspendingEventArgs e)
94 | {
95 | var deferral = e.SuspendingOperation.GetDeferral();
96 | //TODO: Anwendungszustand speichern und alle Hintergrundaktivitäten beenden
97 | deferral.Complete();
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Sample/Sample.Provider/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices.WindowsRuntime;
6 | using Windows.ApplicationModel;
7 | using Windows.ApplicationModel.Activation;
8 | using Windows.Foundation;
9 | using Windows.Foundation.Collections;
10 | using Windows.UI.Xaml;
11 | using Windows.UI.Xaml.Controls;
12 | using Windows.UI.Xaml.Controls.Primitives;
13 | using Windows.UI.Xaml.Data;
14 | using Windows.UI.Xaml.Input;
15 | using Windows.UI.Xaml.Media;
16 | using Windows.UI.Xaml.Navigation;
17 |
18 | namespace Sample.Provider
19 | {
20 | ///
21 | /// Stellt das anwendungsspezifische Verhalten bereit, um die Standardanwendungsklasse zu ergänzen.
22 | ///
23 | sealed partial class App : Application
24 | {
25 | ///
26 | /// Initialisiert das Singletonanwendungsobjekt. Dies ist die erste Zeile von erstelltem Code
27 | /// und daher das logische Äquivalent von main() bzw. WinMain().
28 | ///
29 | public App()
30 | {
31 | this.InitializeComponent();
32 | this.Suspending += this.OnSuspending;
33 | }
34 |
35 | ///
36 | /// Wird aufgerufen, wenn die Anwendung durch den Endbenutzer normal gestartet wird. Weitere Einstiegspunkte
37 | /// werden z. B. verwendet, wenn die Anwendung gestartet wird, um eine bestimmte Datei zu öffnen.
38 | ///
39 | /// Details über Startanforderung und -prozess.
40 | protected override void OnLaunched(LaunchActivatedEventArgs e)
41 | {
42 | var rootFrame = Window.Current.Content as Frame;
43 |
44 | // App-Initialisierung nicht wiederholen, wenn das Fenster bereits Inhalte enthält.
45 | // Nur sicherstellen, dass das Fenster aktiv ist.
46 | if (rootFrame == null)
47 | {
48 | // Frame erstellen, der als Navigationskontext fungiert und zum Parameter der ersten Seite navigieren
49 | rootFrame = new Frame();
50 |
51 | rootFrame.NavigationFailed += this.OnNavigationFailed;
52 |
53 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
54 | {
55 | //TODO: Zustand von zuvor angehaltener Anwendung laden
56 | }
57 |
58 | // Den Frame im aktuellen Fenster platzieren
59 | Window.Current.Content = rootFrame;
60 | }
61 |
62 | if (e.PrelaunchActivated == false)
63 | {
64 | if (rootFrame.Content == null)
65 | {
66 | // Wenn der Navigationsstapel nicht wiederhergestellt wird, zur ersten Seite navigieren
67 | // und die neue Seite konfigurieren, indem die erforderlichen Informationen als Navigationsparameter
68 | // übergeben werden
69 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
70 | }
71 | // Sicherstellen, dass das aktuelle Fenster aktiv ist
72 | Window.Current.Activate();
73 | }
74 | }
75 |
76 | ///
77 | /// Wird aufgerufen, wenn die Navigation auf eine bestimmte Seite fehlschlägt
78 | ///
79 | /// Der Rahmen, bei dem die Navigation fehlgeschlagen ist
80 | /// Details über den Navigationsfehler
81 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
82 | {
83 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
84 | }
85 |
86 | ///
87 | /// Wird aufgerufen, wenn die Ausführung der Anwendung angehalten wird. Der Anwendungszustand wird gespeichert,
88 | /// ohne zu wissen, ob die Anwendung beendet oder fortgesetzt wird und die Speicherinhalte dabei
89 | /// unbeschädigt bleiben.
90 | ///
91 | /// Die Quelle der Anhalteanforderung.
92 | /// Details zur Anhalteanforderung.
93 | private void OnSuspending(object sender, SuspendingEventArgs e)
94 | {
95 | var deferral = e.SuspendingOperation.GetDeferral();
96 | //TODO: Anwendungszustand speichern und alle Hintergrundaktivitäten beenden
97 | deferral.Complete();
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Windows Store app package directory
170 | AppPackages/
171 | BundleArtifacts/
172 |
173 | # Visual Studio cache files
174 | # files ending in .cache can be ignored
175 | *.[Cc]ache
176 | # but keep track of directories ending in .cache
177 | !*.[Cc]ache/
178 |
179 | # Others
180 | ClientBin/
181 | [Ss]tyle[Cc]op.*
182 | ~$*
183 | *~
184 | *.dbmdl
185 | *.dbproj.schemaview
186 | *.pfx
187 | *.publishsettings
188 | node_modules/
189 | orleans.codegen.cs
190 |
191 | # RIA/Silverlight projects
192 | Generated_Code/
193 |
194 | # Backup & report files from converting an old project file
195 | # to a newer Visual Studio version. Backup files are not needed,
196 | # because we have git ;-)
197 | _UpgradeReport_Files/
198 | Backup*/
199 | UpgradeLog*.XML
200 | UpgradeLog*.htm
201 |
202 | # SQL Server files
203 | *.mdf
204 | *.ldf
205 |
206 | # Business Intelligence projects
207 | *.rdl.data
208 | *.bim.layout
209 | *.bim_*.settings
210 |
211 | # Microsoft Fakes
212 | FakesAssemblies/
213 |
214 | # GhostDoc plugin setting file
215 | *.GhostDoc.xml
216 |
217 | # Node.js Tools for Visual Studio
218 | .ntvs_analysis.dat
219 |
220 | # Visual Studio 6 build log
221 | *.plg
222 |
223 | # Visual Studio 6 workspace options file
224 | *.opt
225 |
226 | # Visual Studio LightSwitch build output
227 | **/*.HTMLClient/GeneratedArtifacts
228 | **/*.DesktopClient/GeneratedArtifacts
229 | **/*.DesktopClient/ModelManifest.xml
230 | **/*.Server/GeneratedArtifacts
231 | **/*.Server/ModelManifest.xml
232 | _Pvt_Extensions
233 |
234 | # LightSwitch generated files
235 | GeneratedArtifacts/
236 | ModelManifest.xml
237 |
238 | # Paket dependency manager
239 | .paket/paket.exe
240 |
241 | # FAKE - F# Make
242 | .fake/
243 |
--------------------------------------------------------------------------------
/Sample/Sample.Definition/Options.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Sample.Definition
10 | {
11 |
12 | [DataContract]
13 | [KnownType(typeof(IntOption))]
14 | [KnownType(typeof(StringOption))]
15 | public class TransfareOptions : IReadOnlyList
16 | {
17 |
18 | internal Guid? optionsIdentifyer;
19 | [DataMember]
20 | internal Guid OptionsIdentifyer
21 | {
22 | get
23 | {
24 | if (this.optionsIdentifyer == null)
25 | this.optionsIdentifyer = this.Options.OptionsIdentifier;
26 | return this.optionsIdentifyer.Value;
27 | }
28 | set
29 | {
30 | this.optionsIdentifyer = value;
31 | }
32 | }
33 |
34 | private Options options;
35 | internal Options Options
36 | {
37 | get
38 | {
39 | if (this.options == null)
40 | this.options = new OptionsImpl(this.settings ?? throw new InvalidOperationException(), this.optionsIdentifyer ?? throw new InvalidOperationException());
41 | return this.options;
42 | }
43 | set
44 | {
45 | this.options = value;
46 | }
47 | }
48 |
49 | private AbstractOption[] settings;
50 | [DataMember]
51 | internal AbstractOption[] Settings
52 | {
53 | get
54 | {
55 | if (this.settings == null)
56 | this.settings = this.options?.Settings ?? throw new InvalidOperationException();
57 | return this.settings;
58 | }
59 | set
60 | {
61 | this.settings = value;
62 | }
63 | }
64 |
65 | public int Count => this.Options.Count;
66 |
67 | public AbstractOption this[int index] => this.Options[index];
68 |
69 |
70 |
71 |
72 | public IEnumerator GetEnumerator() => this.Options.GetEnumerator();
73 |
74 | IEnumerator IEnumerable.GetEnumerator() => this.Options.GetEnumerator();
75 |
76 | private class OptionsImpl : Options
77 | {
78 | private readonly Guid guid;
79 | private readonly AbstractOption[] settings;
80 | public OptionsImpl(AbstractOption[] settings, Guid guid)
81 | {
82 | this.settings = settings;
83 | this.guid = guid;
84 | }
85 |
86 | public override Guid OptionsIdentifier => this.guid;
87 |
88 | protected override AbstractOption[] GetSettings() => this.settings;
89 |
90 | }
91 | }
92 |
93 | public abstract class Options : IReadOnlyList
94 | {
95 | public abstract Guid OptionsIdentifier { get; }
96 |
97 | public AbstractOption this[int index]
98 | {
99 | get
100 | {
101 | return this.Settings[index];
102 | }
103 | }
104 |
105 | public int Count => this.Settings.Length;
106 |
107 | private AbstractOption[] settings;
108 |
109 | public AbstractOption[] Settings
110 | {
111 | get
112 | {
113 | this.settings = this.settings ?? GetSettings();
114 | return this.settings;
115 | }
116 | }
117 |
118 | protected abstract AbstractOption[] GetSettings();
119 |
120 | public IEnumerator GetEnumerator()
121 | {
122 | return this.Settings.OfType().GetEnumerator();
123 | }
124 |
125 | IEnumerator IEnumerable.GetEnumerator()
126 | {
127 | return this.Settings.GetEnumerator();
128 | }
129 | }
130 |
131 | [DataContract]
132 | public class AbstractOption
133 | {
134 | public AbstractOption(string name, string description)
135 | {
136 | this.Name = name;
137 | this.Description = description;
138 | }
139 | [DataMember]
140 | public string Name { get; private set; }
141 | [DataMember]
142 | public string Description { get; private set; }
143 |
144 | }
145 |
146 | [DataContract]
147 | public class IntOption : AbstractOption
148 | {
149 | public IntOption(string name, string description, int min, int max) : base(name, description)
150 | {
151 | this.Min = min;
152 | this.Max = max;
153 | }
154 | [DataMember]
155 | public int Min { get; private set; }
156 | [DataMember]
157 | public int Max { get; private set; }
158 | [DataMember]
159 | public int Value { get; set; }
160 | }
161 |
162 | [DataContract]
163 | public class StringOption : AbstractOption
164 | {
165 | public StringOption(string name, string description) : base(name, description)
166 | {
167 |
168 | }
169 | [DataMember]
170 | public string Value { get; set; }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/AppPlugin/AbstractPluginWithOptins.cs:
--------------------------------------------------------------------------------
1 | using AppPlugin.PluginList;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Runtime.Serialization;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Xml;
11 | using Windows.ApplicationModel.AppService;
12 | using Windows.ApplicationModel.Background;
13 | using Windows.Foundation.Collections;
14 |
15 | namespace AppPlugin
16 | {
17 | ///
18 | /// Abstract class that can be implemented to define a simple Plugin that provides one Function that takes an additional option argument.
19 | ///
20 | /// The Type that will be passed to the funtion. (Must have a valid )
21 | /// The return type of the function. (Must have a valid )
22 | /// The Type that will be used to pass the options to f.
23 | /// The type that will be used to report progress. (Must have a valid )
24 | public abstract class AbstractPlugin : AbstractBasePlugin
25 | {
26 |
27 |
28 | ///
29 | /// Instanziate the Plugin.
30 | ///
31 | ///
32 | /// Normaly an AppService uses its own process without UI. It also does not provide a SyncronisationContext. This results that async/await calls will run in the ThreadPool. This includes the Progress report. If the Plugin spans many Tasks, progress will be reported with higher latency.
33 | ///
34 | /// Discrips if the code should be called using a SyncronisationContext.
35 | public AbstractPlugin(bool useSyncronisationContext = true) : base(useSyncronisationContext)
36 | {
37 |
38 | }
39 |
40 | ///
41 | /// Returns an Object that Lists the Availaible Plugins.
42 | ///
43 | ///
44 | /// The length must be less or equal to 39, because of a limitation of the appmanifest.
45 | ///
46 | ///
47 | /// the length of is 40 or greater.
48 | ///
49 | /// The Plugin name defined in the appmanifest.
50 | /// The > ListAsync(string pluginName)
52 | {
53 | var pluginList = new PluginList(pluginName);
54 | await pluginList.InitAsync();
55 | return pluginList;
56 | }
57 |
58 | ///
59 | /// Provides the Funktionality of this Plugin.
60 | ///
61 | /// The Input Parameter.
62 | /// The options that contains additional configuration parameter for the function.
63 | /// The Progress that will report data to the Client.
64 | /// The cancel token.
65 | /// The result of the execution.
66 | protected abstract Task ExecuteAsync(TIn input, TOption options, IProgress progress, CancellationToken cancelToken);
67 |
68 | ///
69 | /// Generates the Prototype Options the client can manipulate and pass back to the Plugin.
70 | ///
71 | /// The prototype options.
72 | protected abstract Task GetDefaultOptionsAsync();
73 |
74 |
75 | internal override async Task RequestRecivedAsync(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
76 | {
77 |
78 | if (args.Request.Message.ContainsKey(OPTIONS_REQUEST_KEY))
79 | {
80 | var options = await GetDefaultOptionsAsync();
81 |
82 | var optionString = Helper.Serilize(options);
83 | var valueSet = new ValueSet();
84 | valueSet.Add(RESULT_KEY, optionString);
85 | await args.Request.SendResponseAsync(valueSet);
86 |
87 | }
88 | else
89 | await base.RequestRecivedAsync(sender, args);
90 | }
91 |
92 |
93 | internal override async Task PerformStartAsync(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args, Guid? id, CancellationTokenSource cancellationTokenSource)
94 | {
95 | var inputString = args.Request.Message[START_KEY] as String;
96 | var optionString = args.Request.Message[OPTION_KEY] as String;
97 |
98 | var input = Helper.DeSerilize(inputString);
99 | var options = Helper.DeSerilize(optionString);
100 |
101 | var progress = new Progress(async r =>
102 | {
103 | var data = Helper.Serilize(r);
104 | var dataSet = new ValueSet();
105 | dataSet.Add(PROGRESS_KEY, data);
106 | dataSet.Add(ID_KEY, id);
107 | await sender.SendMessageAsync(dataSet);
108 | });
109 |
110 | var output = await ExecuteAsync(input, options, progress, cancellationTokenSource.Token);
111 | return output;
112 | }
113 |
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/AppPlugin/AbstractBasePlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Xml;
10 | using Nito.AsyncEx;
11 | using Windows.ApplicationModel.AppService;
12 | using Windows.ApplicationModel.Background;
13 | using Windows.Foundation.Collections;
14 |
15 | namespace AppPlugin
16 | {
17 | [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
18 | public abstract class AbstractBasePlugin : IBackgroundTask
19 | {
20 |
21 | internal AbstractBasePlugin(bool useSyncronisationContext)
22 | {
23 | this.useSyncronisationContext = useSyncronisationContext;
24 | }
25 |
26 | internal const string START_KEY = "Start";
27 | internal const string PROGRESS_KEY = "Progress";
28 | internal const string CANCEL_KEY = "Cancel";
29 | internal const string OPTIONS_REQUEST_KEY = "OptionRequested";
30 | internal const string ID_KEY = "Id";
31 | internal const string RESULT_KEY = "Result";
32 | internal const string ERROR_KEY = "Error";
33 | internal const string OPTION_KEY = "Option";
34 |
35 | private BackgroundTaskDeferral dereffal;
36 | private Dictionary idDirectory = new Dictionary();
37 | private readonly bool useSyncronisationContext;
38 | private AsyncContextThread worker;
39 |
40 | void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)
41 | {
42 | if (this.useSyncronisationContext)
43 | this.worker = new Nito.AsyncEx.AsyncContextThread();
44 |
45 |
46 | this.dereffal = taskInstance.GetDeferral();
47 |
48 | var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
49 | details.AppServiceConnection.RequestReceived += this.AppServiceConnection_RequestReceivedAsync;
50 | details.AppServiceConnection.ServiceClosed += this.AppServiceConnection_ServiceClosed; ;
51 | taskInstance.Canceled += this.TaskInstance_Canceled;
52 |
53 | }
54 |
55 | private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
56 | {
57 | this.worker?.Dispose();
58 | this.dereffal?.Complete();
59 | this.dereffal = null;
60 | }
61 |
62 | private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
63 | {
64 | this.worker?.Dispose();
65 | this.dereffal?.Complete();
66 | this.dereffal = null;
67 | }
68 |
69 | private async void AppServiceConnection_RequestReceivedAsync(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
70 | {
71 | var messageDereffal = args.GetDeferral();
72 | try
73 | {
74 | // if we have a worker we use that.
75 | if (this.worker != null)
76 | await this.worker.Factory.Run(() => RequestRecivedAsync(sender, args));
77 | else
78 | await RequestRecivedAsync(sender, args);
79 |
80 | }
81 | finally
82 | {
83 | messageDereffal.Complete();
84 | }
85 | }
86 |
87 | internal virtual async Task RequestRecivedAsync(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
88 | {
89 | if (args.Request.Message.ContainsKey(START_KEY))
90 | await StartMessageAsync(sender, args);
91 | else if (args.Request.Message.ContainsKey(CANCEL_KEY))
92 | CancelMessage(sender, args);
93 | }
94 |
95 | private void CancelMessage(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
96 | {
97 |
98 | if (!args.Request.Message.ContainsKey(CANCEL_KEY))
99 | return;
100 |
101 | if (!args.Request.Message.ContainsKey(ID_KEY))
102 | return;
103 |
104 |
105 | var id = (Guid)args.Request.Message[ID_KEY];
106 | var shouldCancel = (bool)args.Request.Message[CANCEL_KEY];
107 | if (!shouldCancel)
108 | return;
109 |
110 | if (!this.idDirectory.ContainsKey(id))
111 | return;
112 |
113 | this.idDirectory[id].Cancel();
114 |
115 | }
116 |
117 |
118 | private async Task StartMessageAsync(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
119 | {
120 | Guid? id = null;
121 | try
122 | {
123 | id = (Guid)args.Request.Message[ID_KEY];
124 | if (this.idDirectory.ContainsKey(id.Value))
125 | throw new Exceptions.PluginException("Start was already send.");
126 | var cancellationTokenSource = new CancellationTokenSource();
127 | this.idDirectory.Add(id.Value, cancellationTokenSource);
128 |
129 | object output = await PerformStartAsync(sender, args, id, cancellationTokenSource);
130 |
131 | var outputString = Helper.Serilize(output);
132 | var valueSet = new Windows.Foundation.Collections.ValueSet();
133 | valueSet.Add(ID_KEY, id.Value);
134 | valueSet.Add(RESULT_KEY, outputString);
135 | await args.Request.SendResponseAsync(valueSet);
136 |
137 | }
138 | catch (Exception e)
139 | {
140 | var valueSet = new ValueSet();
141 | valueSet.Add(ERROR_KEY, e.Message);
142 | valueSet.Add(ID_KEY, id.Value);
143 | await args.Request.SendResponseAsync(valueSet);
144 | }
145 | finally
146 | {
147 | if (id.HasValue)
148 | this.idDirectory.Remove(id.Value);
149 | }
150 | }
151 |
152 | internal abstract Task PerformStartAsync(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args, Guid? id, CancellationTokenSource cancellationTokenSource);
153 |
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/Sample/Sample.Definition/Sample.Definition.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6606B2A6-C0D6-4FE9-8F0C-7329D564F832}
8 | Library
9 | Properties
10 | Sample.Definition
11 | Sample.Definition
12 | de-DE
13 | UAP
14 | 10.0.14393.0
15 | 10.0.14393.0
16 | 14
17 | 512
18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 |
20 |
21 | AnyCPU
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
27 | prompt
28 | 4
29 |
30 |
31 | AnyCPU
32 | pdbonly
33 | true
34 | bin\Release\
35 | TRACE;NETFX_CORE;WINDOWS_UWP
36 | prompt
37 | 4
38 |
39 |
40 | x86
41 | true
42 | bin\x86\Debug\
43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
44 | ;2008
45 | full
46 | x86
47 | false
48 | prompt
49 |
50 |
51 | x86
52 | bin\x86\Release\
53 | TRACE;NETFX_CORE;WINDOWS_UWP
54 | true
55 | ;2008
56 | pdbonly
57 | x86
58 | false
59 | prompt
60 |
61 |
62 | ARM
63 | true
64 | bin\ARM\Debug\
65 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
66 | ;2008
67 | full
68 | ARM
69 | false
70 | prompt
71 |
72 |
73 | ARM
74 | bin\ARM\Release\
75 | TRACE;NETFX_CORE;WINDOWS_UWP
76 | true
77 | ;2008
78 | pdbonly
79 | ARM
80 | false
81 | prompt
82 |
83 |
84 | x64
85 | true
86 | bin\x64\Debug\
87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
88 | ;2008
89 | full
90 | x64
91 | false
92 | prompt
93 |
94 |
95 | x64
96 | bin\x64\Release\
97 | TRACE;NETFX_CORE;WINDOWS_UWP
98 | true
99 | ;2008
100 | pdbonly
101 | x64
102 | false
103 | prompt
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | {d35e5f0f-601c-43bf-82d6-89f51ac6aa8b}
118 | AppPlugin
119 |
120 |
121 |
122 | 15.0
123 |
124 |
125 |
132 |
--------------------------------------------------------------------------------
/AppPlugin/AppPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}
8 | Library
9 | Properties
10 | AppPlugin
11 | AppPlugin
12 | en-US
13 | UAP
14 | 10.0.14393.0
15 | 10.0.14393.0
16 | 14
17 | 512
18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 |
20 |
21 | AnyCPU
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
27 | prompt
28 | 4
29 |
30 |
31 | AnyCPU
32 | pdbonly
33 | true
34 | bin\Release\
35 | TRACE;NETFX_CORE;WINDOWS_UWP
36 | prompt
37 | 4
38 |
39 |
40 | x86
41 | true
42 | bin\x86\Debug\
43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
44 | ;2008
45 | full
46 | x86
47 | false
48 | prompt
49 |
50 |
51 | x86
52 | bin\x86\Release\
53 | TRACE;NETFX_CORE;WINDOWS_UWP
54 | true
55 | ;2008
56 | pdbonly
57 | x86
58 | false
59 | prompt
60 |
61 |
62 | ARM
63 | true
64 | bin\ARM\Debug\
65 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
66 | ;2008
67 | full
68 | ARM
69 | false
70 | prompt
71 |
72 |
73 | ARM
74 | bin\ARM\Release\
75 | TRACE;NETFX_CORE;WINDOWS_UWP
76 | true
77 | ;2008
78 | pdbonly
79 | ARM
80 | false
81 | prompt
82 |
83 |
84 | x64
85 | true
86 | bin\x64\Debug\
87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
88 | ;2008
89 | full
90 | x64
91 | false
92 | prompt
93 |
94 |
95 | x64
96 | bin\x64\Release\
97 | TRACE;NETFX_CORE;WINDOWS_UWP
98 | true
99 | ;2008
100 | pdbonly
101 | x64
102 | false
103 | prompt
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | 14.0
127 |
128 |
129 |
136 |
--------------------------------------------------------------------------------
/Sample/Sample.Component/Sample.Component.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D9FD4BC5-0130-4314-87D1-0FE386F922E9}
8 | winmdobj
9 | Properties
10 | Sample.Component
11 | Sample.Component
12 | de-DE
13 | UAP
14 | 10.0.14393.0
15 | 10.0.14393.0
16 | 14
17 | 512
18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 | false
20 |
21 |
22 | AnyCPU
23 | true
24 | full
25 | false
26 | bin\Debug\
27 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
28 | prompt
29 | 4
30 |
31 |
32 | AnyCPU
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE;NETFX_CORE;WINDOWS_UWP
37 | prompt
38 | 4
39 |
40 |
41 | x86
42 | true
43 | bin\x86\Debug\
44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
45 | ;2008
46 | full
47 | x86
48 | false
49 | prompt
50 |
51 |
52 | x86
53 | bin\x86\Release\
54 | TRACE;NETFX_CORE;WINDOWS_UWP
55 | true
56 | ;2008
57 | pdbonly
58 | x86
59 | false
60 | prompt
61 |
62 |
63 | ARM
64 | true
65 | bin\ARM\Debug\
66 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
67 | ;2008
68 | full
69 | ARM
70 | false
71 | prompt
72 |
73 |
74 | ARM
75 | bin\ARM\Release\
76 | TRACE;NETFX_CORE;WINDOWS_UWP
77 | true
78 | ;2008
79 | pdbonly
80 | ARM
81 | false
82 | prompt
83 |
84 |
85 | x64
86 | true
87 | bin\x64\Debug\
88 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
89 | ;2008
90 | full
91 | x64
92 | false
93 | prompt
94 |
95 |
96 | x64
97 | bin\x64\Release\
98 | TRACE;NETFX_CORE;WINDOWS_UWP
99 | true
100 | ;2008
101 | pdbonly
102 | x64
103 | false
104 | prompt
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | {D35E5F0F-601C-43BF-82D6-89F51AC6AA8B}
120 | AppPlugin
121 |
122 |
123 | {6606b2a6-c0d6-4fe9-8f0c-7329d564f832}
124 | Sample.Definition
125 |
126 |
127 |
128 | 15.0
129 |
130 |
131 |
138 |
--------------------------------------------------------------------------------
/AppPlugin/PluginList/PluginList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Runtime.Serialization;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Windows.Input;
11 | using System.Xml;
12 | using Windows.ApplicationModel;
13 | using Windows.ApplicationModel.AppExtensions;
14 | using Windows.ApplicationModel.AppService;
15 | using Windows.Foundation.Collections;
16 | using Windows.UI.Core;
17 | using Windows.UI.Xaml.Media.Imaging;
18 |
19 | namespace AppPlugin.PluginList
20 | {
21 |
22 | public class PluginList : AbstractPluginList.PluginProvider>
23 | {
24 |
25 | internal PluginList(string pluginName) : base(pluginName)
26 | {
27 |
28 | }
29 |
30 | internal override PluginProvider CreatePluginProvider(AppExtension ext, string serviceName)
31 | => new PluginProvider(ext, serviceName);
32 |
33 | public new sealed class PluginProvider : AbstractPluginList.PluginProvider, IPlugin
34 | {
35 |
36 | internal PluginProvider(AppExtension ext, string serviceName) : base(ext, serviceName)
37 | {
38 | }
39 |
40 | private Task GetPluginConnection(IProgress progress, CancellationToken cancelTokem) => PluginConnection.CreateAsync(this.ServiceName, this.Extension, progress, cancelTokem);
41 |
42 | public async Task ExecuteAsync(TIn input, IProgress progress = null, CancellationToken cancelTokem = default(CancellationToken))
43 | {
44 | using (var plugin = await GetPluginConnection(progress, cancelTokem))
45 | return await plugin.ExecuteAsync(input);
46 | }
47 |
48 | }
49 |
50 | private sealed class PluginConnection : IDisposable
51 | {
52 | private readonly AppServiceConnection connection;
53 | private bool isDisposed;
54 | private readonly IProgress progress;
55 | private readonly CancellationToken cancelTokem;
56 | private readonly Guid id = Guid.NewGuid();
57 |
58 | private PluginConnection(AppServiceConnection connection, IProgress progress, CancellationToken cancelTokem = default(CancellationToken))
59 | {
60 | this.connection = connection;
61 | connection.ServiceClosed += this.Connection_ServiceClosed;
62 | connection.RequestReceived += this.Connection_RequestReceived;
63 | this.progress = progress;
64 | this.cancelTokem = cancelTokem;
65 | cancelTokem.Register(this.Canceld);
66 | }
67 |
68 | private async void Canceld()
69 | {
70 | var valueSet = new ValueSet();
71 |
72 | valueSet.Add(AbstractPlugin