{"id":1316,"date":"2012-02-16T15:04:26","date_gmt":"2012-02-16T14:04:26","guid":{"rendered":"http:\/\/www.hjgode.de\/wp\/?p=1316"},"modified":"2012-02-17T17:06:07","modified_gmt":"2012-02-17T16:06:07","slug":"mobile-development-compact-framework-managed-extension-framework-mef","status":"publish","type":"post","link":"http:\/\/www.hjgode.de\/wp\/2012\/02\/16\/mobile-development-compact-framework-managed-extension-framework-mef\/","title":{"rendered":"Mobile Development &#8211; Compact Framework: Managed Extension Framework (MEF)"},"content":{"rendered":"<p>Hello<\/p>\n<p>this post describes a way to load class libraries (DLLs) dynamically on demand in your compact framework application.<\/p>\n<h1>What is it good for?<\/h1>\n<h2>Hardware abstraction. Load only matching Libraries.<\/h2>\n<p>Organize your development for different devices. You will be able to only load the right hardware (device) dependent libraries. You are able to use a hardware abstraction layer.<\/p>\n<p>Normally, you add a reference to an assembly during development in Visual Studio. Now, when the application starts on the device, it will try to load this assembly. If it contains hardware dependent code, like a barcode scanner library, the load of your application may fail.<\/p>\n<p>Using the techniques described here, you can avoid this and direct your app to only load device matching libraries.<\/p>\n<h2>Plugin usage<\/h2>\n<p>You can write a Compact Framework application that will load and work with plugins. These reside in DLLs and can be added or removed on demand.<\/p>\n<p>You can for example write an application launcher that will list the installed extensions. In example for a Transport and Logistic application you can have a truck loading and a truck unloading extension. If you have to update one of the plugins, you only need to replace the plugin DLL, the rest of the application (for example Login forms, Information screens, connection management) remains unchanged.<\/p>\n<h1>DLL loading in C\/C++<\/h1>\n<p>Loading libs dynamically is well known in C\/C++. You simply use LoadLibrary(dllName) and then you can get the addresses to known library functions and use these.<\/p>\n<p>Static linking: Adding a reference in a compact framework (SmartDevice) application inside Visual Studio is like adding a header and lib file to a C\/C++ application.<\/p>\n<h1>DLL loading in Compact Framework<\/h1>\n<p>You can also use the above in C#\/VB.NET.<\/p>\n<p>[codesyntax lang=&#8221;csharp&#8221;]<\/p>\n<pre>namespace ConsoleApplication1\r\n{\r\n  class Program\r\n  {\r\n    static IClass1 GetIClass1(string filename)\r\n    {\r\n      Assembly classLibrary1 = null;\r\n      using (FileStream fs = File.Open(filename, FileMode.Open))\r\n      {\r\n        using (MemoryStream ms = new MemoryStream())\r\n        {\r\n          byte[] buffer = new byte[1024];\r\n          int read = 0;\r\n          while ((read = fs.Read(buffer, 0, 1024))&gt;0)\r\n            ms.Write(buffer, 0, read);\r\n          classLibrary1 = Assembly.Load(ms.ToArray());\r\n        }\r\n      }\r\n      foreach (Type type in classLibrary1.GetExportedTypes())\r\n      {\r\n        if (type.GetInterface(\"IClass1\") != null)\r\n          return Activator.CreateInstance(type) as IClass1;\r\n      }\r\n\r\n      throw new Exception(\"no class found that implements interface IClass1\");\r\n    }\r\n\r\n    static void Main(string[] args)\r\n    {\r\n      IClass1 class1 = GetIClass1(\"ClassLibrary1.dll\");\r\n      class1.DoSomething();\r\n    }\r\n  }\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>[source: http:\/\/social.msdn.microsoft.com\/forums\/en-US\/clr\/thread\/093c3606-e68e-46f4-98a1-f2396d3f88ca\/], may not work without change in CF.<\/p>\n<p><!--more-->Using writing all the C\/C++ LoadLibrary\/GetProcAddress or the above for all your library functions\u00a0 is very time consuming and error-prone.<\/p>\n<p>There is another way using class interfaces and libraries for hardware dependent code described at MSDN: <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa446489.aspx\" target=\"_blank\">Barcode Scanners and the Compact Framework<\/a>. The disadvantage of this solution is, that you have to add references to all different possible implementation assemblies: in the example, you have to add a ref to the Intermec barcode scanner implementation and to the symbol barcode scanner. Imagine if you have to manage this for 4 and more manufacturer and not only for barcode scanners but also for other OEM vendor features (WLAN, keyboard).<\/p>\n<p>So, looking for a better solution, I found the <strong>Managed Extensibility Framework<\/strong> (MEF) and fortunately a Pocket MEF (the compact framework compatible variant). MEF was developed as a community project with technology previews at <a href=\"http:\/\/mef.codeplex.com\/\" target=\"_blank\">codeplex<\/a>. It now is part of NET 4.0 framework.<br \/>\nPocket MEF is also hosted a <a href=\"http:\/\/pocketmef.codeplex.com\/\" target=\"_blank\">codeplex<\/a>, it follows the main technology previews until CTP8.1. Although the full MEF has already reached version 2, the Pocket MEF is sufficiant to be very usefull.<\/p>\n<h1>Pocket MEF<\/h1>\n<p>I will describe how you can use PocketMEF to write an application that will automatically load the right hardware dependent DLLs. We will use PocketMEF to implement a Hardware Abstraction Layer (HAL). PocketMEF will load the right assemblies during runtime on demand using a file name pattern.<\/p>\n<h2>Use Interfaces<\/h2>\n<p>This step is also used in the article at http:\/\/msdn.microsoft.com\/en-us\/library\/aa446489.aspx. Using interfaces or factory classes ensures, that your &#8220;plugins&#8221; or OEM modules have all the same interface.<\/p>\n<p>Hardware abstraction: Implement the different OEM dependent class libs<br \/>\nLet PocketMEF load the right class libs<\/p>\n<p>Plugin use: Implement different plugins using the same interface<br \/>\nLet PocketMEF load all matching plugins<\/p>\n<h1>The sample solution MEFdemo<\/h1>\n<p>I have done a sample application that shows both, hardware abstraction and plugin usage. The Visual Studio 2008 Windows Mobile 6 Prof. solution defines a main application, two different contracts (interfaces) and some extensions that fullfill the interfaces.<\/p>\n<p><a href=\"http:\/\/www.hjgode.de\/wp\/2012\/02\/16\/mobile-development-compact-framework-managed-extension-framework-mef\/solution\/\" rel=\"attachment wp-att-1323\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1323\" title=\"Viual Studio Solution\" src=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/solution-300x288.jpg\" alt=\"\" width=\"300\" height=\"288\" srcset=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/solution-300x288.jpg 300w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/solution-150x144.jpg 150w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/solution.jpg 448w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Unfortunately, the solution is more complex, as it shows both aspects. OK, here is a design schema:<\/p>\n<p><a href=\"http:\/\/www.hjgode.de\/wp\/2012\/02\/16\/mobile-development-compact-framework-managed-extension-framework-mef\/mefdemo-design\/\" rel=\"attachment wp-att-1324\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1324\" title=\"mefdemo-design\" src=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mefdemo-design.png\" alt=\"\" width=\"734\" height=\"479\" srcset=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mefdemo-design.png 734w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mefdemo-design-150x97.png 150w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mefdemo-design-300x195.png 300w\" sizes=\"(max-width: 734px) 100vw, 734px\" \/><\/a><\/p>\n<p>You see, we have one IAppPlugin and one IBarcodeScanControl interface. Then there are two Forms that implement IAppPlugin and one of that uses an IBarcodeScanControl.<\/p>\n<h3>The IAppPlugin Interface<\/h3>\n<pre>namespace MEFdemo1.AppContracts\r\n{\r\n\u00a0\u00a0\u00a0 \/\/describe a public appPlugin interface (contract)\r\n\u00a0\u00a0\u00a0 public interface IAppPlugin : IComponent\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Bitmap appBitmap{ get; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 System.Windows.Forms.DialogResult DialogResult { get; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string sAppText { get; }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string sReturnData { get; }\r\n\u00a0\u00a0\u00a0 }\r\n}<\/pre>\n<h3>An IAppPlugin implementation<\/h3>\n<p>The simple AppPlugin1 Form implements this interface and exports it.<\/p>\n<pre>[codesyntax lang=\"csharp\"]\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Drawing;\r\nusing System.Text;\r\nusing System.Windows.Forms;\r\n\r\nusing System.ComponentModel;\r\nusing System.ComponentModel.Composition;\r\n\r\nusing MEFdemo1.AppContracts;\r\n\r\nnamespace AppPlugin1\r\n{\r\n\u00a0\u00a0\u00a0 [PartCreationPolicy(CreationPolicy.NonShared)]\r\n\u00a0\u00a0\u00a0 [Export(typeof(IAppPlugin))]\r\n\u00a0\u00a0\u00a0 public partial class UserForm1 : Form, IAppPlugin\r\n\u00a0\u00a0\u00a0 {\r\n...<\/pre>\n<pre>[\/codesyntax]<\/pre>\n<h3>The AppPlugin2 uses IBarcodeControl<\/h3>\n<p>This form imports the IBarcodeControl and exports IAppPlugin.<\/p>\n<pre>[codesyntax lang=\"csharp\"]<\/pre>\n<pre>using System;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing System.Data;\r\nusing System.Drawing;\r\nusing System.Text;\r\nusing System.Windows.Forms;\r\n\r\nusing System.ComponentModel.Composition;\r\nusing System.ComponentModel.Composition.Hosting;\r\nusing System.ComponentModel.Composition.Diagnostics;\r\n\r\nusing MEFdemo1.HAL.DeviceControlContracts;\r\nusing MEFdemo1.AppContracts;\r\n\r\nnamespace AppPlugin2\r\n{\r\n    [PartCreationPolicy(CreationPolicy.NonShared)]\r\n    [Export(typeof(IAppPlugin))]\r\n    public partial class BarcodeForm : Form, IAppPlugin\r\n    {\r\n    ...\r\n    }\r\n        \/\/[Import(typeof(IBarcodeScanControl))]\r\n        \/\/if Import is used here, the catalog is unable to find the control!\r\n        private IBarcodeScanControl conScan;\r\n\r\n        DirectoryCatalog catalog2;\r\n        CompositionContainer container2;\r\n\r\n        public BarcodeForm()\r\n        {\r\n            InitializeComponent();\r\n            try\r\n            {\r\n                string sPath=\"\";\r\n                if (isIntermec)\r\n                    sPath = \"MEFdemo1.HAL.Intermec.*Control*.dll\";\r\n                else\r\n                    sPath = \"MEFdemo1.HAL.ACME.*Control*.dll\";\r\n\r\n                \/\/I was unable to use the different catalog and let it look in a subfolder\r\n                \/\/so the plugin names are used as a filter\r\n                catalog2 = new DirectoryCatalog(\".\", sPath);\r\n\r\n                foreach (string s in catalog2.LoadedFiles)\r\n                    System.Diagnostics.Debug.WriteLine(s);\r\n\r\n                container2 = new CompositionContainer(catalog2);\r\n\r\n                container2.ComposeParts(this);\r\n...<\/pre>\n<pre>[\/codesyntax]<\/pre>\n<p>The usable BarcodeControl is loaded by using a different file pattern for the DirectoryCatalog. So only one BarcodeControl is loaded.<\/p>\n<h3>The MainForm<\/h3>\n<p>The main form scans the application dir for IAppPlugins and lists them using there bitmap property.<\/p>\n<pre>[codesyntax lang=\"csharp\"]<\/pre>\n<pre>...\r\n        \/\/we will import all available plugins\r\n        [ImportMany(typeof(IAppPlugin))]\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 private int iPluginCount = 0;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 DirectoryCatalog catalog;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 CompositionContainer container;\r\n...\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public MainForm()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 InitializeComponent();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catalog = new DirectoryCatalog(\".\", \"MEFdemo1.Plugins.*.dll\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 container = new CompositionContainer(catalog);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 container.ComposeParts(this);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 drawPlugins();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catch (Exception ex)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MessageBox.Show(\"No Plugins loaded: \" + ex.Message);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n[\/codesyntax]<\/pre>\n<p>drawPlugins will draw the images inside MainForm using pictureboxes and applies a click handler for these.<\/p>\n<pre>[codesyntax lang=\"csharp\"]<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 void MainForm_Click(object sender, EventArgs e)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string sApp = ((PictureBox)sender).Tag.ToString();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 System.Diagnostics.Debug.WriteLine(sApp);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foreach (IAppPlugin iApp in plugins)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (iApp.sAppText.Equals(sApp))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ((System.Windows.Forms.Form)iApp).ShowDialog();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 continue;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/pre>\n<pre>[\/codesyntax]<\/pre>\n<p>Here is a screenshot of the composed parts:<\/p>\n<p><a href=\"http:\/\/www.hjgode.de\/wp\/2012\/02\/16\/mobile-development-compact-framework-managed-extension-framework-mef\/mainform\/\" rel=\"attachment wp-att-1330\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1330\" title=\"mainform\" src=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mainform.gif\" alt=\"\" width=\"240\" height=\"320\" srcset=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mainform.gif 240w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mainform-112x150.gif 112w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/mainform-225x300.gif 225w\" sizes=\"(max-width: 240px) 100vw, 240px\" \/><\/a><\/p>\n<p>When you click one of the pictureboxes, the plugins form is shown: either the BarcodeForm or the simple UserForm:<\/p>\n<p><a href=\"http:\/\/www.hjgode.de\/wp\/2012\/02\/16\/mobile-development-compact-framework-managed-extension-framework-mef\/barcodeform\/\" rel=\"attachment wp-att-1329\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1329\" title=\"barcodeform\" src=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/barcodeform.gif\" alt=\"\" width=\"240\" height=\"320\" srcset=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/barcodeform.gif 240w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/barcodeform-112x150.gif 112w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/barcodeform-225x300.gif 225w\" sizes=\"(max-width: 240px) 100vw, 240px\" \/><\/a> \u00a0<a href=\"http:\/\/www.hjgode.de\/wp\/2012\/02\/16\/mobile-development-compact-framework-managed-extension-framework-mef\/userform\/\" rel=\"attachment wp-att-1331\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1331\" title=\"UserForm\" src=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/UserForm.gif\" alt=\"\" width=\"240\" height=\"320\" srcset=\"http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/UserForm.gif 240w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/UserForm-112x150.gif 112w, http:\/\/www.hjgode.de\/wp\/wp-content\/uploads\/2012\/02\/UserForm-225x300.gif 225w\" sizes=\"(max-width: 240px) 100vw, 240px\" \/><\/a><\/p>\n<p>The programs dir reflects all the contracts and plugins:<\/p>\n<pre>intermec.datacollection.cf3.5.dll                            intermec barcode hardware wrapper\r\nintermec.devicemanagement.smartsystem.itcssapi.dll           intermec software wrapper\r\nMEFdemo1.exe                                                 the application\r\nmefdemo1.appcontracts.dll                                    the AppPlugin contract\r\nmefdemo1.devicecontrolcontracts.dll                          the BarcodePlugin contract\r\nMEFdemo1.HAL.ACME.BarcodeControl2.dll                        one BarcodeControl (the generic implementation)\r\nMEFdemo1.HAL.Intermec.BarcodeControl1.dll                    second BarcodeControl (intermec dependent)\r\nMEFdemo1.Plugins.AppPlugin1.dll                              the UserForm application plugin\r\nMEFdemo1.Plugins.AppPlugin2.dll                              the BarcodeForm application plugin\r\npocket.componentmodel.initialization.dll                     PocketMEF runtime\r\npocket.system.componentmodel.composition.dll                 PocketMEF runtime<\/pre>\n<p>If you remove one of the AppPlugin DLL files and then start MEFdemo, only the remaining Plugin is shown.<\/p>\n<p>Although I implemented all plugins in there own class library projects, you can combine multiple plugins into one project and so will get less DLLs. The disadvantage is that you cant simply update only one these plugins, you have then to replace the whole lib.<\/p>\n<p>Source code is hosted at code.google.com\/p\/pocketmef\/source\/<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello this post describes a way to load class libraries (DLLs) dynamically on demand in your compact framework application. What is it good for? Hardware abstraction. Load only matching Libraries. Organize your development for different devices. You will be able to only load the right hardware (device) dependent libraries. You are able to use a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[178,239,3],"tags":[452,169,315,451,453,450,449,15],"class_list":["post-1316","post","type-post","status-publish","format-standard","hentry","category-codeproject","category-itc-programming","category-programming","tag-assembly","tag-compact-framework","tag-dll","tag-dynamic","tag-hardware-abstraction-layer","tag-managed-extensibility-framework","tag-mef","tag-windows-mobile"],"_links":{"self":[{"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/posts\/1316"}],"collection":[{"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/comments?post=1316"}],"version-history":[{"count":14,"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/posts\/1316\/revisions"}],"predecessor-version":[{"id":1336,"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/posts\/1316\/revisions\/1336"}],"wp:attachment":[{"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/media?parent=1316"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/categories?post=1316"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.hjgode.de\/wp\/wp-json\/wp\/v2\/tags?post=1316"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}