Quantcast
Channel: MSDN Blogs
Viewing all 12366 articles
Browse latest View live
โ†ง

Creating dynamic SSIS package [Object model] and using OleDBSource & OleDBDestination internally fails in SSIS 2016

$
0
0

ย 

Issue:

While dynamically creating SSIS packages using the object model and referencing the following SSIS libraries, you may receive the following exception thrown

SSIS Libraries referenced:

C:Program Files (x86)Microsoft SQL Server130SDKAssemblies

  1. SqlServer.DTSPipelineWrap.dll
  2. SQLServer.ManagedDTS.dll
  3. SQLServer.DTSRuntimeWrap.dll

ย 

ย Error Message:

System.Runtime.InteropServices.COMExceptionโ€™ occurred in ConsoleApplication1.exe

Additional information: Exception from HRESULT: 0xC0048021

{โ€œException from HRESULT: 0xC0048021โ€}

ย ย  at Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSDesigntimeComponent100.ProvideComponentProperties()

ย ย  at ConsoleApplication1.Program.Main(String[] args) in c:UsersAdministratorDocumentsVisual Studio 2013ProjectsConsoleApplication1ConsoleApplication1Program.cs:line 27

ย ย  at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)

ย ย  at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

ย ย  at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

ย ย  at System.Threading.ThreadHelper.ThreadStart_Context(Object state)

ย ย  at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)

ย ย  at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)

ย ย  at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

ย  ย at System.Threading.ThreadHelper.ThreadStart()

ย 

Steps to reproduce the issue:

  1. Use the below C# code in a Console Application:

โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”

using System;ย 

using Microsoft.SqlServer.Dts.Runtime;ย 

using Microsoft.SqlServer.Dts.Pipeline;ย 

using Microsoft.SqlServer.Dts.Pipeline.Wrapper;

ย namespace ConsoleApplication1

{

ย ย ย  class Program

ย ย ย  {

ย ย ย ย ย ย ย  static void Main(string[] args)

ย ย ย ย ย ย ย  {

ย ย ย ย ย ย ย ย ย ย ย  Package package = new Package();

ย ย ย ย ย ย ย ย ย ย ย  Executable e = package.Executables.Add(โ€œSTOCK:PipelineTaskโ€);

ย ย ย ย ย ย ย ย ย ย ย  TaskHost thMainPipe = e as TaskHost;

ย ย ย ย ย ย ย ย ย ย ย  MainPipe dataFlowTask = thMainPipe.InnerObject as MainPipe;

ย 

ย ย ย ย ย ย ย ย ย ย ย  // Create the source component.ย ย ย 

ย ย ย ย ย ย ย ย ย ย ย ย IDTSComponentMetaData100 source =

ย ย ย ย ย ย ย ย ย ย ย ย ย  dataFlowTask.ComponentMetaDataCollection.New();

ย ย ย ย ย ย ย ย ย ย ย  source.ComponentClassID = โ€œDTSAdapter.OleDbSourceโ€;

ย ย ย ย ย ย ย ย ย ย ย CManagedComponentWrapper srcDesignTime = source.Instantiate();

ย ย ย ย ย ย ย ย ย ย ย  srcDesignTime.ProvideComponentProperties();

ย 

ย ย ย ย ย ย ย ย ย ย ย  // Create the destination component.ย 

ย ย ย ย ย ย ย ย ย ย ย ย IDTSComponentMetaData100 destination =

ย ย ย ย ย ย ย ย ย ย ย ย ย  dataFlowTask.ComponentMetaDataCollection.New();

ย ย ย ย ย ย ย ย ย ย ย  destination.ComponentClassID = โ€œDTSAdapter.OleDbDestinationโ€;

ย ย ย ย ย ย ย ย ย ย ย  CManagedComponentWrapper destDesignTime = destination.Instantiate();

ย ย ย ย ย ย ย ย ย ย ย  destDesignTime.ProvideComponentProperties();

ย 

ย ย ย  ย ย ย ย ย ย ย ย // Create the path.ย 

ย ย ย ย ย ย ย ย ย ย ย ย IDTSPath100 path = dataFlowTask.PathCollection.New();

ย ย ย ย ย ย ย ย ย ย ย  path.AttachPathAndPropagateNotifications(source.OutputCollection[0],

ย ย ย ย ย ย ย ย ย ย ย ย ย  destination.InputCollection[0]);

ย ย ย ย ย ย ย  }

ย ย ย  }

}

โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”

  1. Add the reference from:
  • ย  ย  ย  ย  ย  C:Program Files (x86)Microsoft SQL Server130SDKAssembliesMicrosoft.SQLServer.ManagedDTS.dll
  • ย  ย  ย  ย  ย  C:Program Files (x86)Microsoft SQL Server130SDKAssembliesMicrosoft.SQLServer.DTSRuntimeWrap.dll
  • ย  ย  ย  ย  ย C:Program Files (x86)Microsoft SQL Server130SDKAssembliesMicrosoft.SQLServer.DTSPipelineWrap.dll
  1. Debug the code and you may receive the above exception in the function : srcDesignTime.ProvideComponentProperties();

ย 

Cause:

The reason for the exception was that the version independent COM ProgID was not registered to point to the latest version, so loading of OLEDB SOURCE connection manager threw above error The code is using version independent ProgIDs:

โ€œDTSAdapter.OleDbSourceโ€ &ย  โ€œDTSAdapter.OleDbDestinationโ€.The COM spec says, the version independent ย ProgIDs should always load the latest version. But these ProgIDs are not registered.

ย 

Resolution/Workaround:

As workaround, modify the ProgIDs to the names of SSIS 2016 IDs and use version specific ProgIDs. wiz.

DTSAdapter.OleDbSource.5 & DTSAdapter.OleDbDestination.5 rather than DTSAdapter.OleDbSource & DTSAdapter.OleDbDestination in the above code sample.

ย 

You may find the information of these ProgIDs from the System registry.

For e.g.

The ProgID โ€œDTSAdapter.OleDbSource.5โ€ is registered to point to SSIS 2016 OLEDB Source.

under HKEY_CLASSES_ROOTCLSID{657B7EBE-0A54-4C0E-A80E-7A5BD9886C25}

Similarly, the ProgID โ€œDTSAdapter.OLEDBDestination.5โ€ is registered to point to SSIS 2016 OLE DB Destination are under

HKEY_CLASSES_ROOTCLSID{7B729B0A-4EA5-4A0D-871A-B6E7618E9CFB}

ย 

If you still have the issues, then please contact Microsoft CSS team for further assistance.

ย 

DISCLAIMER:

Any Sample code is provided for the purpose of illustration only and is not intended to be used in a production environment. ย ANY SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED โ€œAS ISโ€ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

ย 

ย 

Author:ย  ย  ย  ย Ranjit Mondal โ€“ Support Engineer, SQL Server BI Developer team, Microsoft

Reviewer:ย ย ย Krishnakumar Rukmangathanย โ€“ย Support Escalation Engineer, SQL Server BI Developer team, Microsoft

โ†ง

ใƒ‡ใƒใ‚คใ‚นใƒžใƒใƒผใ‚ธใƒฃใƒผใฎ [่กจ็คบ] ใ‚’ [ใƒ‡ใƒใ‚คใ‚น (ๆŽฅ็ถšๅˆฅ)] ใซๅˆ‡ใ‚Šๆ›ฟใˆใ‚‹

$
0
0

ๅˆ‡ใ‚Šๅˆ†ใ‘ใฎใŸใ‚ใซใ€ๆŽฅ็ถšใ—ใŸใƒ‡ใƒใ‚คใ‚นใจ PC ใฎใƒใ‚นใจใฎ้–“ใงใฉใ‚“ใชใƒ‰ใƒฉใ‚คใƒใƒผใŒๅ‹•ใ„ใฆใ„ใ‚‹ใ‹็Ÿฅใ‚ŠใŸใ„ใจๆ€ใฃใŸใ“ใจใฏใ‚ใ‚Šใพใ™ใ‹๏ผŸ

ย 

็š†ใ•ใ‚“ใ€ใ“ใ‚“ใซใกใฏใ€‚Windows Driver Kit ใ‚ตใƒใƒผใƒˆใƒใƒผใƒ ใฎๆดฅ็”ฐใงใ™ใ€‚ไปŠๅ›žใฏใ€ใใ‚“ใช็š†ๆง˜ใซใ€ใƒ‡ใƒใ‚คใ‚น ใƒžใƒใƒผใ‚ธใƒฃใƒผใฎ [่กจ็คบ] ใ‚’ใ€ใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใฎ [ใƒ‡ใƒใ‚คใ‚น (็จฎ้กžๅˆฅ)] ใ‹ใ‚‰ [ใƒ‡ใƒใ‚คใ‚น (ๆŽฅ็ถšๅˆฅ)] ใซๅˆ‡ใ‚Šๆ›ฟใˆใ€ๅ„ใƒ‡ใƒใ‚คใ‚น ใƒŽใƒผใƒ‰ใ‹ใ‚‰ใƒ‰ใƒฉใ‚คใƒใƒผใ‚’็ขบ่ชใงใใ‚‹ใจใ“ใ‚ใ‚’ใŠ่ฆ‹ใ›ใ—ใŸใ„ใจๆ€ใ„ใพใ™ใ€‚ใพใŸใ€ๅŒใ˜ใƒ‰ใƒฉใ‚คใƒใƒผๆง‹ๆˆใ‚’ใ‚ซใƒผใƒใƒซใƒ‡ใƒใƒƒใ‚ฌใƒผใงใƒ‡ใƒใ‚คใ‚น ใƒŽใƒผใƒ‰ใ‚’ใŸใฉใฃใฆ็ขบ่ชใ™ใ‚‹ๆ–นๆณ•ใ‚‚ใ”็ดนไป‹ใ—ใพใ™ใ€‚

ย 

ไปŠๅ›žใ€ไพ‹ใจใ—ใฆ Windows 10 (1607) x86 ใ‚’ไฝฟใ„ใพใ™ใ€‚

ย 

1. [ใ‚นใ‚ฟใƒผใƒˆ] ใƒกใƒ‹ใƒฅใƒผใ‚’ๅณใ‚ฏใƒชใƒƒใ‚ฏใ—ใฆใ€[ใƒ‡ใƒใ‚คใ‚น ใƒžใƒใƒผใ‚ธใƒฃใƒผ] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใฆใ€ใƒ‡ใƒใ‚คใ‚น ใƒžใƒใƒผใ‚ธใƒฃใƒผใ‚’่ตทๅ‹•ใ—ใพใ™ใ€‚

2. ไปปๆ„ใฎใƒ‡ใƒใ‚คใ‚นใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใพใ™ใ€‚ไปŠๅ›žใฏไพ‹ใจใ—ใฆใ€[ใƒ‡ใ‚ฃใ‚นใ‚ฏใƒ‰ใƒฉใ‚คใƒ–] ใซใ‚ใ‚‹ [Virtual HD ATA Device] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใพใ™ใ€‚

ย 

clip_image002

ย 

3. ไธŠๅ›ณใฎใ‚ˆใ†ใซใ€[่กจ็คบ] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ™ใ‚‹ใจใ€[ใƒ‡ใƒใ‚คใ‚น (็จฎ้กžๅˆฅ)] ใจใชใฃใฆใ„ใ‚‹ใฎใงใ€[ใƒ‡ใƒใ‚คใ‚น (ๆŽฅ็ถšๅˆฅ)] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใพใ™ใ€‚

ย 

clip_image004

ย 

4. ไธŠๅ›ณใฎ้€šใ‚Šใ€ๅฏพ่ฑกใƒ‡ใƒใ‚คใ‚นใŒๆŽฅ็ถšใ•ใ‚Œใฆใ„ใ‚‹ๅ ดๆ‰€ใŒใƒ„ใƒชใƒผ็Šถใซ่กจ็คบใ•ใ‚Œใพใ™ใ€‚ไธŠ่จ˜ใฎไพ‹ใงใฏใ€ไปฅไธ‹ใฎใƒ„ใƒชใƒผใซใชใฃใฆใ„ใพใ™ใ€‚

ย 

ACPI x86-based PC

โ†’ Microsoft ACPI-Compliant System

ย ย  โ†’ PCI ใƒใ‚น

ย ย ย ย  โ†’ Intel(R) 82371AB/EB PCI Bus Master IDE Controller

ย ย ย ย ย ย ย ย  โ†’ ATA Channel 0

ย ย ย ย ย ย ย ย ย ย ย  โ†’ Virtual HD ATA Device

ย 

5. ๅ„ใƒŽใƒผใƒ‰ใ‚’ๅณใ‚ฏใƒชใƒƒใ‚ฏใ—ใฆ [ใƒ—ใƒญใƒ‘ใƒ†ใ‚ฃ] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใ€[ใƒ‰ใƒฉใ‚คใƒใƒผ] ใ‚ฟใƒ–ใ‚’้–‹ใ„ใฆ [ใƒ‰ใƒฉใ‚คใƒใƒผใฎ่ฉณ็ดฐ] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใพใ™ใ€‚

ย 

5-1. ใพใšใฏใ€Virtual HD ATA Device ใ‚’่ฆ‹ใฆใฟใพใ™ใ€‚ไปฅไธ‹ใฎใ‚ˆใ†ใซ disk.sys, EhStorClass.sys, partmgr.sys, vmstorfl.sys ใŒๅ…ฅใฃใฆใ„ใฆใ€ๅ„ใƒ•ใ‚กใ‚คใƒซใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ™ใ‚‹ใจๅผŠ็คพ่ฃฝใงใ‚ใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚

ย 

clip_image006

ย 

5-2. ๆฌกใซใ€ไธ€ใคไธŠใฎใƒŽใƒผใƒ‰ใงใ‚ใ‚‹ ATA Channel 0 ใ‚’่ฆ‹ใฆใฟใพใ™ใ€‚Atapi.sys, ataport.sys ใŒใ‚ใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚

ย 

clip_image008

ย 

5-3. ๆฌกใซใ€Intel(R) 82371AB/EB PCI Bus Master IDE Controller ใ‚’่ฆ‹ใฆใฟใพใ™ใ€‚Atapi.sys, ataport.sys, intelide.sys, pciidex.sys ใŒใ‚ใ‚‹ใฎใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚

ย 

clip_image010

ย 

5-4. ๆฌกใซ PCI ใƒใ‚นใ‚’่ฆ‹ใฆใฟใพใ™ใ€‚ใใฎๅใฎ้€šใ‚Šใ€pci.sys ใŒใ‚ใ‚Šใพใ™ใ€‚

ย 

clip_image012

ย 

ย 

6. ไธŠ่จ˜ใ‚’ใ‚ซใƒผใƒใƒซใƒ‡ใƒใƒƒใ‚ฌโ€•ใง่ฆ‹ใฆใฟใพใ™ใ€‚

ย 

6-1. ใพใšใฏใ€disk.sys ใฎใƒ‡ใƒใ‚คใ‚นใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใ‚’ๆŽขใ—ใพใ™ใ€‚

ย 

kd> !drvobj disk

Driver object (8ebe86f8) is for:

Driverdisk

Driver Extension List: (id , addr)

(8a657bd0 8ebeee20)ย 

Device Object list:

8d700a80ย 

ย 

6-2. ๆœ€ๅพŒใซ่กจ็คบใ•ใ‚ŒใŸใƒ‡ใƒใ‚คใ‚นใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใฎใ‚ขใƒ‰ใƒฌใ‚นใ‚’ไฝฟใฃใฆใ€ใƒ‡ใƒใ‚คใ‚นใ‚นใ‚ฟใƒƒใ‚ฏใ‚’่ฆ‹ใฆใฟใพใ™ใ€‚5-1 ใง็ขบ่ชใ—ใŸ disk.sys ใฎไธŠใซ partmgr.sys ใŒใ‚ใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚ใพใŸใ“ใฎใƒ‡ใƒใ‚คใ‚นใƒŽใƒผใƒ‰ใงใฏใ€atapi.sys ใฎใƒ‡ใƒใ‚คใ‚นใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใŒ PDO ใงใ‚ใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚ใƒ‡ใƒใ‚คใ‚นใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใ‚„ใƒ‡ใƒใ‚คใ‚นใ‚นใ‚ฟใƒƒใ‚ฏใซใคใ„ใฆใฏ K ้‡Œใ•ใ‚“ใฎใ‚จใƒณใƒˆใƒช (Device Object ใจ Device Stack) ใ‚’ใ”ๅ‚็…งใใ ใ•ใ„ใ€‚

ย 

kd> !devstack 8d700a80

ย  !DevObjย ย  !DrvObjย ย ย ย ย ย ย ย ย ย ย  !DevExtย ย  ObjectName

ย  8d7006e0ย  Driverpartmgrย ย ย  8d700798ย 

> 8d700a80ย  Driverdiskย ย ย ย ย ย  8d700b38ย  DR0

ย  8d6c1790ย  Driverstorfltย ย ย  8d6c1f10ย 

ย  8ebd9920ย  DriverACPIย ย ย ย ย ย  8eb0b568ย 

ย  8ebd7878ย  Driveratapiย ย ย ย ย  8ebd7930ย  IdeDeviceP0T0L0-0

!DevNode 8ebdd008 :

ย  DeviceInst is โ€œIDEDiskVirtual_HD______________________________1.1.0___5&35dc7040&0&0.0.0โ€

ย  ServiceName is โ€œdiskโ€

ย 

6-3. !DevNode ใจใ—ใฆ่กจ็คบใ•ใ‚ŒใŸใƒ‡ใƒใ‚คใ‚นใƒŽใƒผใƒ‰ใ‚’่ฆ‹ใฆใฟใพใ™ใ€‚PDO ใŒไธŠ่จ˜ atapi.sys ใฎใƒ‡ใƒใ‚คใ‚นใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใจๅŒใ˜ (0x8ebd7878) ใงใ‚ใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚ใ“ใฎใƒ‡ใƒใ‚คใ‚นใƒŽใƒผใƒ‰ใŒๆœซ็ซฏใชใฎใง Child ใฎใ‚ขใƒ‰ใƒฌใ‚นใŒ NULL (0) ใงใ™ใ€‚่ฆชใƒŽใƒผใƒ‰ใงใ‚ใ‚‹ Parent ใฎใ‚ขใƒ‰ใƒฌใ‚น (0x8ebd3e30) ใŒ็ขบ่ชใงใใพใ™ใ€‚

ย 

kd> !DevNode 8ebdd008

DevNode 0x8ebdd008 for PDO 0x8ebd7878

ย  Parent 0x8ebd3e30ย ย  Sibling 0000000000ย ย  Child 0000000000ย ย 

ย  InstancePath is โ€œIDEDiskVirtual_HD______________________________1.1.0___5&35dc7040&0&0.0.0โ€

ย  ServiceName is โ€œdiskโ€

ย  State = DeviceNodeStarted (0x308)

ย  Previous State = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[08] = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[07] = DeviceNodeEnumeratePending (0x30c)

ย  StateHistory[06] = DeviceNodeStarted (0x308)

ย  StateHistory[05] = DeviceNodeStartPostWork (0x307)

ย  StateHistory[04] = DeviceNodeStartCompletion (0x306)

ย  StateHistory[03] = DeviceNodeResourcesAssigned (0x304)

ย  StateHistory[02] = DeviceNodeDriversAdded (0x303)

ย  StateHistory[01] = DeviceNodeInitialized (0x302)

ย  StateHistory[00] = DeviceNodeUninitialized (0x301)

ย  StateHistory[19] = Unknown State (0x0)

ย  StateHistory[18] = Unknown State (0x0)

ย  StateHistory[17] = Unknown State (0x0)

ย  StateHistory[16] = Unknown State (0x0)

ย  StateHistory[15] = Unknown State (0x0)

ย  StateHistory[14] = Unknown State (0x0)

ย  StateHistory[13] = Unknown State (0x0)

ย  StateHistory[12] = Unknown State (0x0)

ย  StateHistory[11] = Unknown State (0x0)

ย  StateHistory[10] = Unknown State (0x0)

ย  StateHistory[09] = Unknown State (0x0)

ย  Flags (0x20000130)ย  DNF_ENUMERATED, DNF_IDS_QUERIED,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_NO_RESOURCE_REQUIRED, DNF_NO_UPPER_DEVICE_FILTERS

ย  UserFlags (0x00000008)ย  DNUF_NOT_DISABLEABLE

ย  DisableableDepends = 1 (including self)

ย 

6-4. ่ฆชใƒŽใƒผใƒ‰ใ‚’ !devnode ใง่ฆ‹ใฆใฟใพใ™ใ€‚Child ใฎใ‚ขใƒ‰ใƒฌใ‚นใŒใ€6-3 ใฎใ‚‚ใฎ (0x8ebdd008) ใจๅŒใ˜ใงใ‚ใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚

ย 

kd> !devnode 8ebd3e30

DevNode 0x8ebd3e30 for PDO 0x8ebd2ce0

ย  Parent 0x8eb7fa80ย ย  Sibling 0x8ebd3c58ย ย  Child 0x8ebdd008ย ย 

ย  InstancePath is โ€œPCIIDEIDEChannel4&10bf2f88&0&0โ€

ย  ServiceName is โ€œatapiโ€

ย  State = DeviceNodeStarted (0x308)

ย  Previous State = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[09] = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[08] = DeviceNodeEnumeratePending (0x30c)

ย  StateHistory[07] = DeviceNodeStarted (0x308)

ย  StateHistory[06] = DeviceNodeStartPostWork (0x307)

ย  StateHistory[05] = DeviceNodeStartCompletion (0x306)

ย  StateHistory[04] = DeviceNodeStartPending (0x305)

ย  StateHistory[03] = DeviceNodeResourcesAssigned (0x304)

ย  StateHistory[02] = DeviceNodeDriversAdded (0x303)

ย  StateHistory[01] = DeviceNodeInitialized (0x302)

ย  StateHistory[00] = DeviceNodeUninitialized (0x301)

ย  StateHistory[19] = Unknown State (0x0)

ย  StateHistory[18] = Unknown State (0x0)

ย  StateHistory[17] = Unknown State (0x0)

ย  StateHistory[16] = Unknown State (0x0)

ย  StateHistory[15] = Unknown State (0x0)

ย  StateHistory[14] = Unknown State (0x0)

ย  StateHistory[13] = Unknown State (0x0)

ย  StateHistory[12] = Unknown State (0x0)

ย  StateHistory[11] = Unknown State (0x0)

ย  StateHistory[10] = Unknown State (0x0)

ย  Flags (0x6c0000f0)ย  DNF_ENUMERATED, DNF_IDS_QUERIED,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_HAS_BOOT_CONFIG, DNF_BOOT_CONFIG_RESERVED,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_NO_LOWER_DEVICE_FILTERS, DNF_NO_LOWER_CLASS_FILTERS,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_NO_UPPER_DEVICE_FILTERS, DNF_NO_UPPER_CLASS_FILTERS

ย  UserFlags (0x00000008)ย  DNUF_NOT_DISABLEABLE

ย  DisableableDepends = 2 (including self)

ย 

6-5. PDO ใฎใ‚ขใƒ‰ใƒฌใ‚นใ‹ใ‚‰ใƒ‡ใƒใ‚คใ‚นใ‚นใ‚ฟใƒƒใ‚ฏใ‚’่ฆ‹ใฆใฟใพใ™ใ€‚Atapi.sys ใฎใƒ‡ใƒใ‚คใ‚นใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใŒ FDO ใจใ—ใฆใ‚ใ‚Šใ€ใ“ใฎใƒ‡ใƒใ‚คใ‚นใƒŽใƒผใƒ‰ใฏใ€5-2 ใง่ฆ‹ใŸใ€ŒATA Channel 0ใ€ใจๅŒใ˜ใ ใจใ‚ใ‹ใ‚Šใพใ™ใ€‚PDO ใŒ intelide.sys ใฎใƒ‡ใƒใ‚คใ‚นใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆใชใฎใงใ€5-3 ใฎใ€ŒIntel(R) 82371AB/EB PCI Bus Master IDE Controllerใ€ใซใคใชใŒใฃใฆใ„ใ‚‹ใฎใ ใ‚ใ†ใจๆŽจๅฏŸใงใใพใ™ใ€‚

ย 

kd> !devstack 0x8ebd2ce0

ย  !DevObjย ย  !DrvObjย ย ย ย ย ย ย ย ย ย ย  !DevExtย ย  ObjectName

ย  88695028ย  Driveratapiย ย ย ย ย  886950e0ย  IdePort0

ย  8ebc9620ย  DriverACPIย ย ย ย ย ย  8eb0b7a0ย 

> 8ebd2ce0ย  Driverintelideย ย  8ebd2d98ย  PciIde0Channel0

!DevNode 8ebd3e30 :

ย  DeviceInst is โ€œPCIIDEIDEChannel4&10bf2f88&0&0โ€

ย  ServiceName is โ€œatapiโ€

ย 

6-6. ๅŒๆง˜ใซ Parent ใ‚’ใŸใฉใฃใฆใ€PDO ใฎใƒ‡ใƒใ‚คใ‚นใ‚นใ‚ฟใƒƒใ‚ฏใ‚’่กจ็คบใ—ใฆใ„ใใจไปฅไธ‹ใฎใ‚ˆใ†ใซใชใ‚Šใพใ™ใ€‚

ย 

kd> !devnode 0x8eb7fa80

DevNode 0x8eb7fa80 for PDO 0x8eb7e030

ย  Parent 0x887eccc0ย ย  Sibling 0x8eb7f8a8ย ย  Child 0x8ebd3e30ย ย 

ย  InstancePath is โ€œPCIVEN_8086&DEV_7111&SUBSYS_00000000&REV_013&267a616a&0&39โ€

ย  ServiceName is โ€œintelideโ€

ย  State = DeviceNodeStarted (0x308)

ย  Previous State = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[09] = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[08] = DeviceNodeEnumeratePending (0x30c)

ย  StateHistory[07] = DeviceNodeStarted (0x308)

ย  StateHistory[06] = DeviceNodeStartPostWork (0x307)

ย  StateHistory[05] = DeviceNodeStartCompletion (0x306)

ย  StateHistory[04] = DeviceNodeStartPending (0x305)

ย  StateHistory[03] = DeviceNodeResourcesAssigned (0x304)

ย  StateHistory[02] = DeviceNodeDriversAdded (0x303)

ย  StateHistory[01] = DeviceNodeInitialized (0x302)

ย  StateHistory[00] = DeviceNodeUninitialized (0x301)

ย  StateHistory[19] = Unknown State (0x0)

ย  StateHistory[18] = Unknown State (0x0)

ย  StateHistory[17] = Unknown State (0x0)

ย  StateHistory[16] = Unknown State (0x0)

ย  StateHistory[15] = Unknown State (0x0)

ย  StateHistory[14] = Unknown State (0x0)

ย  StateHistory[13] = Unknown State (0x0)

ย  StateHistory[12] = Unknown State (0x0)

ย  StateHistory[11] = Unknown State (0x0)

ย  StateHistory[10] = Unknown State (0x0)

ย  Flags (0x6c0000f0)ย  DNF_ENUMERATED, DNF_IDS_QUERIED,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_HAS_BOOT_CONFIG, DNF_BOOT_CONFIG_RESERVED,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_NO_LOWER_DEVICE_FILTERS, DNF_NO_LOWER_CLASS_FILTERS,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_NO_UPPER_DEVICE_FILTERS, DNF_NO_UPPER_CLASS_FILTERS

ย  UserFlags (0x00000008)ย  DNUF_NOT_DISABLEABLE

ย  DisableableDepends = 2 (including self)

ย 

// PDO ใฎใƒ‡ใƒใ‚คใ‚นใ‚นใ‚ฟใƒƒใ‚ฏใ‚’่กจ็คบ

ย 

kd> !devstack 0x8eb7e030

ย  !DevObjย ย  !DrvObjย ย ย ย ย ย ย ย ย ย ย  !DevExtย ย  ObjectName

ย  8ebd2030ย  Driverintelideย ย  8ebd20e8ย  PciIde0

ย  8eb7e8f8ย  DriverACPIย ย ย ย ย ย  8eb0b9d8ย 

> 8eb7e030ย  Driverpciย ย ย ย ย ย ย  8eb7e0e8ย  NTPNP_PCI0002

!DevNode 8eb7fa80 :

ย  DeviceInst is โ€œPCIVEN_8086&DEV_7111&SUBSYS_00000000&REV_013&267a616a&0&39โ€

ย  ServiceName is โ€œintelideโ€

ย 

// Parent ใฎใƒ‡ใƒใ‚คใ‚นใƒŽใƒผใƒ‰ใ‚’่กจ็คบ

ย 

kd> !devnode 0x887eccc0

DevNode 0x887eccc0 for PDO 0x8e3fd1e0

ย  Parent 0x8869b860ย ย  Sibling 0x8eb0ce00ย ย  Child 0x8eb7fe30ย ย 

ย  InterfaceType 0x5ย  Bus Number 0

ย  InstancePath is โ€œACPIPNP0A03โ€

ย  ServiceName is โ€œpciโ€

ย  State = DeviceNodeStarted (0x308)

ย  Previous State = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[09] = DeviceNodeEnumerateCompletion (0x30d)

ย  StateHistory[08] = DeviceNodeEnumeratePending (0x30c)

ย  StateHistory[07] = DeviceNodeStarted (0x308)

ย  StateHistory[06] = DeviceNodeStartPostWork (0x307)

ย  StateHistory[05] = DeviceNodeStartCompletion (0x306)

ย  StateHistory[04] = DeviceNodeStartPending (0x305)

ย  StateHistory[03] = DeviceNodeResourcesAssigned (0x304)

ย  StateHistory[02] = DeviceNodeDriversAdded (0x303)

ย  StateHistory[01] = DeviceNodeInitialized (0x302)

ย  StateHistory[00] = DeviceNodeUninitialized (0x301)

ย  StateHistory[19] = Unknown State (0x0)

ย  StateHistory[18] = Unknown State (0x0)

ย  StateHistory[17] = Unknown State (0x0)

ย  StateHistory[16] = Unknown State (0x0)

ย  StateHistory[15] = Unknown State (0x0)

ย  StateHistory[14] = Unknown State (0x0)

ย  StateHistory[13] = Unknown State (0x0)

ย  StateHistory[12] = Unknown State (0x0)

ย  StateHistory[11] = Unknown State (0x0)

ย  StateHistory[10] = Unknown State (0x0)

ย  Flags (0x6c0000f0)ย  DNF_ENUMERATED, DNF_IDS_QUERIED,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_HAS_BOOT_CONFIG, DNF_BOOT_CONFIG_RESERVED,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_NO_LOWER_DEVICE_FILTERS, DNF_NO_LOWER_CLASS_FILTERS,

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DNF_NO_UPPER_DEVICE_FILTERS, DNF_NO_UPPER_CLASS_FILTERS

ย  UserFlags (0x00000008)ย  DNUF_NOT_DISABLEABLE

ย  CapabilityFlags (0x000000c0)ย  UniqueID, SilentInstall

ย  DisableableDepends = 4 (including self)

ย 

// PDO ใฎใƒ‡ใƒใ‚คใ‚นใ‚นใ‚ฟใƒƒใ‚ฏใ‚’่กจ็คบใ€‚PCI ใƒใ‚นใซใŸใฉใ‚Š็€ใ„ใŸใ€‚

ย 

kd> !devstack 0x8e3fd1e0

ย  !DevObjย ย  !DrvObjย ย ย ย ย ย ย ย ย ย ย  !DevExtย ย  ObjectName

ย  8ebb9020ย  Driverpciย ย ย ย ย ย ย  8ebb90d8ย 

> 8e3fd1e0ย  DriverACPIย ย ย ย ย ย  8eb0bc10ย  0000000f

!DevNode 887eccc0 :

ย  DeviceInst is โ€œACPIPNP0A03โ€

ย  ServiceName is โ€œpciโ€

ย 

ย 

ไธŠ่จ˜ใ‚’่กŒใ†ใ“ใจใงใ€ๆญฃๅธธ็ณป (ไพ‹ใˆใฐใ‚ฏใƒชใƒผใƒณใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใŸ OS ใฎ็’ฐๅขƒ) ใจ็•ฐๅธธ็ณป (ใŠๅ›ฐใ‚Šใฎ็พ่ฑกใŒ็™บ็”Ÿใ™ใ‚‹็’ฐๅขƒ) ใฎใƒ‰ใƒฉใ‚คใƒใƒผๆง‹ๆˆใฎ้•ใ„ใ‚’ๅˆ‡ใ‚Šๅˆ†ใ‘ใ‚‹ใ“ใจใŒใงใใ‚‹ๅ ดๅˆใŒใ‚ใ‚Šใพใ™ใ€‚็š†ๆง˜ใฎใƒˆใƒฉใƒ–ใƒซใ‚ทใƒฅใƒผใƒ†ใ‚ฃใƒณใ‚ฐใฎไธ€ๅŠฉใจใชใ‚Šใพใ—ใŸใ‚‰ๅนธใ„ใงใ™ใ€‚

โ†ง
โ†ง

.NET Framework 4.6.2 ๅ‘ๅธƒๅ…ฌๅ‘Š

$
0
0

[ๅŽŸๆ–‡ๅ‘่กจๅœฐๅ€]: Announcing .NET Framework 4.6.2

[ๅŽŸๆ–‡ๅ‘่กจๆ—ถ้—ด]: August 2, 2016

ย 

ไปŠๅคฉ๏ผŒๆˆ‘ไปฌๅพˆ้ซ˜ๅ…ดๅœฐๅฎฃๅธƒ.NET Framework 4.6.2 ๅ‘ๅธƒไบ†๏ผ่ฎธๅคšๆ›ดๆ”น้ƒฝๆ˜ฏๅŸบไบŽๆ‚จ็š„ๅ้ฆˆๆ„่ง๏ผŒๅ…ถไธญๅŒ…ๆ‹ฌไธ€ไบ›ๅœจ็”จๆˆทๅ้ฆˆ ๅ’Œๅ้ฆˆ่”็ณปไธญๅฟƒ ๆไบค็š„ๆ„่งๅ’Œๅปบ่ฎฎใ€‚้žๅธธๆ„Ÿ่ฐขๆ‚จ็š„ไธๆ–ญ็š„ๅธฎๅŠฉๅ’Œๅ‚ไธŽ ๏ผ

ย 

่ฟ™ๆฌก็š„ๅ‘ๅธƒๅœจไปฅไธ‹ๅ‡ ไธชๆ–น้ขๆœ‰็€ๅทจๅคง็š„ๆ”น่ฟ›ๅ’Œๆๅ‡๏ผš

ๅœจ.NET Framework 4.6.2 ็š„ๆ›ดๆ”นๅˆ—่กจๅ’Œ ๅบ”็”จ็จ‹ๅบๆŽฅๅฃๅ˜ๅŒ–้›†ไธญ๏ผŒไฝ ๅฏไปฅๆŸฅ็œ‹ๅˆฐๆ‰€ๆœ‰ๆ›ดๆ”น็š„ไธœ่ฅฟใ€‚

ย 

็ซ‹ๅณไธ‹่ฝฝ

็Žฐๅœจ๏ผŒไฝ ๅฏไปฅ้€š่ฟ‡ไปฅไธ‹้€”ๅพ„ๆฅไธ‹่ฝฝ.NET Framework 4.6.2:

ย 

ๅŸบ็ก€ๅบ“็ฑป๏ผˆBCL๏ผ‰

ๅœจBCLไธŠ่ฟ›่กŒไบ†ไปฅไธ‹ๆ”น่ฟ›๏ผš

ๆ”ฏๆŒ้•ฟ่ทฏๅพ„๏ผˆMAXPATH๏ผ‰

ๅœจSystem.IO็š„ๅบ”็”จ็จ‹ๅบๆŽฅๅฃไธญ๏ผŒๆˆ‘ไปฌไฟฎๅคไบ†ๆœ€้•ฟ๏ผˆMAXPATH๏ผ‰ๆ–‡ไปถๅ็งฐ้•ฟๅบฆไธบ260ไธชๅญ—็ฌฆ็š„้™ๅˆถใ€‚ๅœจ็”จๆˆทๅ้ฆˆ็š„้—ฎ้ข˜ไธŠ๏ผŒ่ถ…่ฟ‡4500็”จๆˆทๆๅˆฐไบ†่ฏฅ้—ฎ้ข˜ใ€‚

้€šๅธธๆƒ…ๅ†ตไธ‹๏ผŒ่ฟ™็ง้™ๅˆถไธไผšๅฝฑๅ“ไฝฟ็”จ่€…็š„ๅบ”็”จ็จ‹ๅบ ๏ผˆไพ‹ๅฆ‚๏ผŒไปŽโ€ๆˆ‘็š„ๆ–‡ๆกฃโ€ไธญๅŠ ่ฝฝๆ–‡ไปถ๏ผ‰๏ผŒไฝ†ๆฏ”่พƒๅธธ่ง็š„ๆ˜ฏ๏ผŒๅœจๅผ€ๅ‘ไบบๅ‘˜็š„ๆœบๅ™จไธŠ็”ŸๆˆๅตŒๅฅ—ๅพˆๆทฑ็š„ๆบ็ ๆ ‘ๆˆ–็€ไฝฟ็”จไธ“้—จ็š„ๅทฅๅ…ท๏ผŒ่ฟ˜่ฟ่กŒๅœจUnix๏ผˆ็ปๅธธไผš็”จๅˆฐ้•ฟ่ทฏๅพ„๏ผ‰ใ€‚

ๅœจ.NET Framework 4.6.2ไปฅๅŠไน‹ๅŽ็š„็‰ˆๆœฌไธŠ๏ผŒ่ฟ™ไธชๆ–ฐๅŠŸ่ƒฝๅทฒ็ปๅฏ็”จใ€‚ๆ‚จๅฏไปฅ้€š่ฟ‡ๅœจapp.configๆˆ–่€…web.config็ญ‰้…็ฝฎๆ–‡ไปถไธญ่ฟ›่กŒๅฆ‚ไธ‹่ฎพ็ฝฎ๏ผŒๆฅ่ฎพ็ฝฎไฝ ็š„ๅบ”็”จ็จ‹ๅบ ไปฅๅฎšๅ‘ๅˆฐ.Net4.6.2๏ผš

01

ไฝ ๅฏไปฅ้€š่ฟ‡ไธ‹้ข็š„ๆ–นๅผๆฅ่ฎพ็ฝฎ AppContext ๅผ€ๅ…ณ้…็ฝฎๆ–‡ไปถ๏ผŒไปŽ่€Œๅฐ†ๆญคๅŠŸ่ƒฝๅบ”็”จๅˆฐๆ—ฉๆœŸ็‰ˆๆœฌ็š„.NETๆก†ๆžถๅบ”็”จ็จ‹ๅบไธŠ้ขใ€‚ๆญคๅผ€ๅ…ณๅชๆ”ฏๆŒๅœจ.NET4.6.2ๆก†ๆžถไธŠ่ฟ่กŒ็š„ๅบ”็”จ็จ‹ๅบ ๏ผˆๆˆ–ๆ›ด้ซ˜็‰ˆๆœฌ๏ผ‰ใ€‚

02

ๅœจ็Žฐๆœ‰็š„็ฆๆญขไฝฟ็”จ่ทฏๅพ„ๆฏ”MAXPATH้•ฟ็š„่กŒไธบไธญ๏ผŒ็ผบไนๅฎšๅ‘ๅˆฐ.NET4.6.2ๆก†ๆžถๆˆ–่€…ๆ˜ฏ่ฎพ็ฝฎAppContextๅผ€ๅ…ณใ€‚่ฟ™ๆ˜ฏไธบไบ†็ปดๆŠค็Žฐๆœ‰ๅบ”็”จ็จ‹ๅบ็š„ๅ‘ๅŽๅ…ผๅฎนๆ€งใ€‚

้€š่ฟ‡ไปฅไธ‹ๆ”น่ฟ›๏ผŒไฝฟๅพ—้•ฟ่ทฏๅพ„ๅฏไปฅๅบ”็”จ๏ธฐ

  • ๅ…่ฎธๅคงไบŽ 260 ๅญ—็ฌฆ (MAX_PATH)็š„่ทฏๅพ„ใ€‚ BCL ็ป„ๅ…่ฎธ่ทฏๅพ„้•ฟๅบฆ่ถ…่ฟ‡ MAX_PATH ๆœ€ๅคงๅ…่ฎธ่Œƒๅ›ดใ€‚BCL ๅบ”็”จ็จ‹ๅบๆŽฅๅฃไพ่ต–ๅบ•ๅฑ‚ Win32 ๆ–‡ไปถๆฅ ่ฟ›่กŒ้™ๅˆถๆฃ€ๆŸฅใ€‚
  • ๅฏ็”จๆ‰ฉๅฑ•่ทฏๅพ„่ฏญๆณ•ๅ’Œๆ–‡ไปถๅ‘ฝๅ็ฉบ้—ด(\?, \.). Windows ๅ…ฌๅผ€ไบ†ๅคšไธชๅฏ็”จๅค‡็”จ่ทฏๅพ„่ฎกๅˆ’็š„ๆ–‡ไปถๅ‘ฝๅ็ฉบ้—ดใ€‚ไพ‹ๅฆ‚ๆ‰ฉๅฑ•่ทฏๅพ„่ฏญๆณ•๏ผŒๅ…่ฎธ่ถ…่ฟ‡ 32k ็š„่ทฏๅพ„ๅญ—็ฌฆใ€‚BCL ็Žฐๅœจๆ”ฏๆŒไธ€ไบ›่ทฏๅพ„๏ผŒไพ‹ๅฆ‚๏ธฐ \?้•ฟ่ทฏๅพ„ใ€‚.NET ๆก†ๆžถ็Žฐๅœจไธป่ฆไพ่ต–ไบŽ Windows ่ทฏๅพ„ๆฅ่ฟ›่กŒ่ง„่ŒƒๅŒ–๏ผŒไปฅ้ฟๅ…ๆ— ๆ„ไธญ้˜ปๆญขๅˆๆณ•่ทฏๅพ„ใ€‚ๆ‰ฉๅฑ•่ทฏๅพ„่ฏญๆณ•ๆ˜ฏไธ€ไธชๅพˆๅฅฝ็š„่งฃๅ†ณWindows็‰ˆๆœฌไธๆ”ฏๆŒไฝฟ็”จๅธธ่ง„ๅฝขๅผ็š„้•ฟ่ทฏๅพ„๏ผˆไพ‹ๅฆ‚๏ผŒC:้•ฟ่ทฏ็ป๏ผ‰็š„ๆ–นๆณ•ใ€‚
  • ๆ€ง่ƒฝๆ”น่ฟ›ใ€‚้€š่ฟ‡ๅœจBCLไธญ้‡‡ๅ– Windows ่ทฏๅพ„่ง„่ŒƒๅŒ–ไปฅๅŠๅ‡ๅฐ‘็ฑปไผผ็š„้€ป่พ‘๏ผŒไฝฟๅพ—ๅ…ณไบŽๆ–‡ไปถ่ทฏๅพ„็š„้€ป่พ‘ๆ•ดไฝ“ๆ€ง่ƒฝๅพ—ๅˆฐๆ”น่ฟ›ใ€‚

ๆ›ดๅคš่ฏฆ็ป†็š„ไฟกๆฏ๏ผŒๆ‚จๅฏไปฅๅœจJeremy Kuhne็š„ๅšๅฎขไธญๆ‰พๅˆฐ.

ย 

X509 ่ฏไนฆ็Žฐๅœจๆ”ฏๆŒ FIPS 186-3 ๆ•ฐๅญ—็ญพๅ็ฎ—ๆณ•

.NET ๆก†ๆžถ 4.6.2 ๆทปๅŠ ไบ† FIPS 186-3 ๆ•ฐๅญ—็ญพๅ็ฎ—ๆณ• (DSA) ็š„ๆ”ฏๆŒใ€‚ๆ”ฏๆŒๅฏ†้’ฅ้•ฟๅบฆ่ถ…่ฟ‡ 1024ไฝ็š„X509 ่ฏไนฆใ€‚ๅฎƒ่ฟ˜ๆ”ฏๆŒ่ฎก็ฎ—็ญพๅๅ“ˆๅธŒ็ฎ—ๆณ•็ณปๅˆ—๏ผˆSHA256ใ€ SHA384 ๅ’Œ SHA512๏ผ‰ใ€‚

.NET ๆก†ๆžถ 4.6.1 ๆ”ฏๆŒ FIPS 186-2๏ผŒไฝ†ๆ˜ฏ้™ๅˆถไบ†ๅฏ†้’ฅ้•ฟๅบฆไธ่ƒฝ่ถ…่ฟ‡ 1024ไฝใ€‚

้€š่ฟ‡ไฝฟ็”จๆ–ฐ็š„DSACng็ฑป๏ผŒไฝ ๅฏไปฅๅˆฉ็”จ FIPS 186-3ๆ”ฏๆŒ๏ผŒ่ฟ™ๅฏไปฅไปŽไธ‹้ข็š„็คบไพ‹ไธญ็œ‹ๅˆฐใ€‚

DSA ๅŸบ็ฑปไนŸๅทฒ็ปๆ›ดๆ–ฐ๏ผŒๆ‰€ไปฅๆ‚จๅฏไปฅไฝฟ็”จ FIPS 186-3็š„ๆ”ฏๆŒ่€Œไธ้œ€่ฆ่ฝฌๆขๅˆฐๆ–ฐ็š„ DSACng ็ฑปใ€‚่ฟ™ไธŽไน‹ๅ‰ไธคไธช็‰ˆๆœฌ.NETๆก†ๆžถ็”จไบŽๆ›ดๆ–ฐ RSA ๅ’Œ ECDsa็ฎ—ๆณ•ๅฎž็Žฐไธญ็š„ๆ–นๆณ•็›ธๅŒใ€‚

ย 

ๆ”น่ฟ›็š„ๆคญๅœ†ๆ›ฒ็บฟๅŠ ๅฏ†็ฎ—ๆณ•ๆดพ็”Ÿไพ‹็จ‹

ECDiffieHellmanCng ็ฑป็š„ๅฏ็”จๆ€งๅทฒๅพ—ๅˆฐๆ”น่ฟ›ใ€‚ๅœจ.NET ๆก†ๆžถ็š„ๆคญๅœ†ๆ›ฒ็บฟๅŠ ๅฏ†็ฎ—ๆณ•(ECDH) ็š„ๅฏ†้’ฅๅ่ฎฎๆ‰ง่กŒๅŒ…ๆ‹ฌไธ‰ไธชไธๅŒ็š„ๅฏ†้’ฅๆดพ็”ŸๅŠŸ่ƒฝ(KDF) ไพ‹็จ‹ใ€‚่ฟ™ไบ› KDF ไพ‹็จ‹็Žฐๅœจไปฃ่กจๅ’ŒไนŸ่ขซไธ‰็งไธๅŒ็š„ๆ–นๆณ•ๆ‰€ๆ”ฏๆŒ๏ผŒไฝ ๅฏไปฅไปŽไธ‹้ข็š„็คบไพ‹ไธญ็œ‹ๅˆฐใ€‚

ๅœจ.NET Framework ็š„ๆ—ฉๆœŸ็‰ˆๆœฌไธญ๏ผŒๅฏนไบŽไธ‰ไธชไธๅŒ็š„ไพ‹็จ‹๏ผŒไฝ ๅฟ…้กป็Ÿฅ้“ๆฏไธชไพ‹็จ‹ๅœจECDiffieHellmanCng ็ฑปไธญ้œ€่ฆ่ฎพ็ฝฎ็š„ๅฑžๆ€งๅญ้›†ใ€‚

ย 

ไฟๅญ˜ๅฏ†้’ฅ็š„ๅฏน็งฐๅŠ ๅฏ†ๆ”ฏๆŒ

Windows ๅŠ ๅฏ†ๅบ“ (CNG) ๆ”ฏๆŒๅœจ่ฝฏไปถๅ’Œ็กฌไปถไธŠไฟ็•™ๅฏน็งฐๅฏ†้’ฅใ€‚.NET ๆก†ๆžถ็Žฐๅœจๅ…ฌๅผ€ไบ†่ฟ™็ง CNG ่ƒฝๅŠ›๏ผŒๆญฃๅฆ‚ไธ‹้ข็š„็คบไพ‹ไธญๅฑ•็คบ็š„้‚ฃๆ ทใ€‚

ๆ‚จ้œ€่ฆไฝฟ็”จๅ…ทไฝ“็š„ๅฎž็Žฐ็ฑป๏ผŒๅฆ‚ AesCng็ฑปๆฅไฝฟ็”จๆญคๆ–ฐๅŠŸ่ƒฝ๏ผŒ่€Œไธๆ˜ฏๆ›ดๅธธ่ง็š„ๅทฅๅŽ‚ๆ–นๅผ๏ผŒๅฆ‚Aes.Create()ใ€‚่ฟ™้กน่ฆๆฑ‚ๆ˜ฏ็”ฑไบŽ็‰นๅฎšไบŽๅฎž็Žฐ็š„ๅฏ†้’ฅๅ็งฐๅ’Œๅฏ†้’ฅๆไพ›่€…ใ€‚

ๅœจ AesCng TripleDESCng ็ฑปไธญ๏ผŒๅˆ†ๅˆซไธบ AES ๅ’Œ 3DES ็ฎ—ๆณ•ๆทปๅŠ ไบ†ไฟๅญ˜ๅฏ†้’ฅ็š„ๅฏน็งฐๅŠ ๅฏ†ใ€‚

ย 

SignedXml ๆ”ฏๆŒๅ“ˆๅธŒSHA-2

.NET ๆก†ๆžถ SignedXmlๅฎž็Žฐๆ”ฏๆŒไปฅไธ‹SHA-2 ๅ“ˆๅธŒ็ฎ—ๆณ•

ไฝ ๅฏไปฅๅœจไธ‹้ข็š„ๅฎžไพ‹ไธญ็œ‹ๅˆฐไฝฟ็”จSHA-256ๅฏนXML่ฟ›่กŒ็ญพๅใ€‚

ๆ–ฐ็š„ SignedXml ๅญ—ๆฎตไธญๆทปๅŠ ไบ†ๆ–ฐ็š„ SignedXML URI ๅธธๆ•ฐใ€‚ไธ‹้ขๆ˜พ็คบไบ†ๆ–ฐๅญ—ๆฎตใ€‚

ไธบไบ†ๆ”ฏๆŒ่ฟ™ไบ›็ฎ—ๆณ•๏ผŒ้‚ฃไบ›ๅทฒ็ปๆณจๅ†Œไบ†่‡ชๅฎšไน‰็š„ SignatureDescription ๅค„็†็จ‹ๅบๅˆฐ CryptoConfig็š„ๅบ”็”จ็จ‹ๅบๅฐ†ไผšๅ’Œๅพ€ๅธธไธ€ๆ ท็ปง็ปญ่ฟไฝœ๏ผŒไฝ†ๆ˜ฏๅ› ไธบ็Žฐๅœจๆœ‰ๅนณๅฐ้ป˜่ฎค๏ผŒๆ‰€ไปฅๆณจๅ†ŒCryptoConfigๅทฒ็ปไธๅ†ๆ˜ฏๅฟ…้กป็š„ไบ†ใ€‚

ย 

ๅ…ฌๅ…ฑ่ฏญ่จ€่ฟ่กŒๅบ“๏ผˆCLR๏ผ‰

ๅœจ CLR ๅšไบ†ไปฅไธ‹ๆ”น่ฟ›ใ€‚

็ฉบๅผ•็”จๅผ‚ๅธธ็š„ๆ”น่ฟ›

ๅคงๅฎถๅฏ่ƒฝ้ƒฝ็ปๅކ่ฟ‡ๅนถไธ”่ฐƒๆŸฅ่ฟ‡็ฉบNullReferenceException็š„ๅŽŸๅ› ใ€‚ไธบไบ†ๅœจไปฅๅŽ็š„Visual Studio็‰ˆๆœฌไธญ๏ผŒๅœจ็ฉบๅผ•็”จๆ–น้ขๆไพ›ๆ›ดๅฅฝ็š„่ฐƒ่ฏ•ไฝ“้ชŒ๏ผŒๆˆ‘ไปฌๅฏ็”จไบ†้ƒจๅˆ†ไธŽ Visual Studio ๅ›ข้˜Ÿๅˆไฝœ็š„ๆ–นๅผใ€‚

ๅœจ Visual Studio ไธญ็š„่ฐƒ่ฏ•ไฝ“้ชŒ๏ผŒไพ่ต–ไบŽไธŽไฝ ็š„ไปฃ็ ไฝŽๆฐดๅนณไบคไบ’็š„ๅ…ฌๅ…ฑ่ฏญ่จ€่ฟ่กŒๅบ“่ฐƒ่ฏ•ๅบ”็”จ็จ‹ๅบๆŽฅๅฃใ€‚็Žฐๅœจ๏ผŒๅœจ Visual Studio ไธญ็š„ NullReferenceException ไฝ“้ชŒ็œ‹่ตทๆฅๆ˜ฏ่ฟ™ๆ ท๏ธฐ

ๅœจ่ฟ™ไธช็‰ˆๆœฌไธญ๏ผŒๆˆ‘ไปฌๆ‰ฉๅฑ•ไบ†CLR ่ฐƒ่ฏ•ๅบ”็”จ็จ‹ๅบๆŽฅๅฃ๏ผŒๅฝ“็ฉบๅผ•็”จๅผ‚ๅธธๅผนๅ‡บๆ—ถ๏ผŒๅฐฑๅฏไปฅไฝฟๅพ—่ฐƒ่ฏ•ๅ™จ่ƒฝๅคŸ่ฏทๆฑ‚ๆ›ดๅคš็š„ไฟกๆฏ๏ผŒๅนถไธ”่ฟ›่กŒ้ขๅค–็š„ๅˆ†ๆžใ€‚ๅˆฉ็”จๆญคไฟกๆฏ๏ผŒ่ฐƒ่ฏ•ๅ™จๅฐฑ่ƒฝๅคŸ็กฎๅฎšๅ“ชไบ›ๅผ•็”จไธบ็ฉบ๏ผŒๅนถๅฐ†่ฟ™ไบ›ไฟกๆฏๆไพ›็ป™ไฝ ๏ผŒไฝฟไฝ ็š„ๅทฅไฝœๆ›ดๅŠ ๅฎนๆ˜“ใ€‚

ย 

้ƒจ็ฝฒๆ–นๆกˆ

ClickOnce ่ฟ›่กŒไบ†ไปฅไธ‹ๆ–น้ข็š„ๆ”น่ฟ›ใ€‚

ๆ”ฏๆŒไผ ่พ“ๅฑ‚ๅฎ‰ๅ…จ(TLS)ๅ่ฎฎ 1.1 ๅ’Œ 1.2

ๅœจ้ƒจ็ฝฒๆ–นๆกˆๆ–น้ข๏ผŒๆˆ‘ไปฌไธบ.NET Framework 4.5.2๏ผŒ4.6๏ผŒ4.6.1ไปฅๅŠ4.6.2 ็‰ˆๆœฌๅขžๅŠ ไบ†TLS 1.1 ๅ’Œ 1.2 ็š„ๅ่ฎฎๆ”ฏๆŒใ€‚ๆˆ‘ไปฌ่ฆๆ„Ÿ่ฐข๏ผŒๅœจ็”จๆˆทๅ้ฆˆไธŠ้ขๆŠ•็ฅจ็š„ไฝ ไปฌ๏ผไฝ ไธ้œ€่ฆๅšไปปไฝ•้ขๅค–็š„ๆญฅ้ชคๆฅๅฏ็”จ TLS 1.1 ๆˆ– 1.2 ็š„ๆ”ฏๆŒ๏ผŒๅ› ไธบ้ƒจ็ฝฒๆ–นๆกˆไผšๅœจ่ฟ่กŒๆ—ถ่‡ชๅŠจๆฃ€ๆต‹ๅ“ชไธช TLS ๅ่ฎฎๆ˜ฏๅฟ…้œ€็š„ใ€‚

ๅฎ‰ๅ…จๅฅ—ๆŽฅๅญ—ๅฑ‚ (SSL) ๅ’Œ TLS 1.0 ไธๅ†่ขซไธ€ไบ›็ป„็ป‡ๆŽจ่ๆˆ–ๆ”ฏๆŒใ€‚ไพ‹ๅฆ‚๏ผŒไธบไบ†ๆปก่ถณไป–ไปฌๅœจ็บฟไบ‹ๅŠก็š„่ง„่Œƒ๏ผŒๆ”ฏไป˜ๅก่กŒไธšๅฎ‰ๅ…จๆ ‡ๅ‡†ๅง”ๅ‘˜ไผšๅœจไธบ่ฆๆฑ‚ TLS 1.1 ๆˆ–ๆ›ด้ซ˜็‰ˆๆœฌ่€ŒๅŠชๅŠ›ใ€‚

ไธบไบ†ๅ…ผๅฎน้‚ฃไบ›ไธไผšๆˆ–่€…ไธ่ƒฝๅ‡็บง็š„ๅบ”็”จ็จ‹ๅบ๏ผŒ้ƒจ็ฝฒๆ–นๆกˆ็ปง็ปญๆ”ฏๆŒTLS 1.0ใ€‚ๆˆ‘ไปฌๅปบ่ฎฎๅˆ†ๆžๆ‚จๆ‰€ๆœ‰ไฝฟ็”จ็š„ SSL ๅ’Œ TLS 1.0ใ€‚่ฏทๅ‚้˜…KBๅบ“๏ผŒๅนถไฝฟ็”จ้‡Œ้ข็š„้“พๆŽฅๆฅไธ‹่ฝฝไฟฎๅค็จ‹ๅบ.NET ๆก†ๆžถ4.6๏ผŒ4.6.1ๅ’Œ4.5.2

ย 

ๅฎขๆˆท็ซฏ่ฏไนฆๆ”ฏๆŒ

็Žฐๅœจๅฏไปฅๅฐ†้ƒจ็ฝฒๆ–นๆกˆ็š„ๅบ”็”จ็จ‹ๅบๆ‰˜็ฎกๅœจ่™šๆ‹Ÿ็›ฎๅฝ•ไธญ๏ผŒ่€Œ่ฟ™ไธช่™šๆ‹Ÿ็›ฎๅฝ•่ฆๆฑ‚ๅฏ็”จไบ†SSLๅนถไธ”ๆœ‰ๅฎขๆˆท็ซฏ่ฏไนฆใ€‚ๅœจ่ฏฅ้…็ฝฎไธ‹๏ผŒๅฝ“็”จๆˆท่ฎฟ้—ฎๆŸไธชๅบ”็”จ็จ‹ๅบ็š„ๆ—ถๅ€™๏ผŒๅฐ†ไผš่ขซๆ็คบ่ฆ้€‰ๆ‹ฉไป–ไปฌ็š„่ฏไนฆใ€‚ๅฆ‚ๆžœๅฎขๆˆท็ซฏ่ฏไนฆ่ขซ่ฎพ็ฝฎไธบโ€ๅฟฝ็•ฅโ€๏ผŒ้‚ฃไนˆ้ƒจ็ฝฒๆ–นๆกˆๅบ”็”จ็จ‹ๅบๅฐ†ไธไผšๆ็คบ้€‰ๆ‹ฉ่ฏไนฆใ€‚

ๅœจไปฅๅ‰็š„็‰ˆๆœฌไธญ๏ผŒ่™ฝ็„ถๅบ”็”จ็จ‹ๅบไปฅๅŒๆ ท็š„ๆ–นๅผๆ‰˜็ฎก๏ผŒไฝ†ๆ˜ฏๅบ”็”จ็จ‹ๅบ็š„ClickOnce้ƒจ็ฝฒๆœ€็ปˆไผš่ขซ็ปˆๆญข๏ผŒๅนถไธ”ๅผนๅ‡บๆ‹’็ป่ฎฟ้—ฎ้”™่ฏฏใ€‚

clickonce_ssl

ย 

ASP.NET

ASP.NET ไธญๆๅ‡บไบ†ไปฅไธ‹ๆ”น่ฟ›ใ€‚่ฏทๅ‚้˜… ASP.NET ๆ ธๅฟƒ 1.0ๅ…ฌๅ‘Š๏ผŒไปฅไบ†่งฃ ASP.NET ๆ ธๅฟƒ็š„ๅ…ทไฝ“ๆ”น่ฟ›ใ€‚

ๆœฌๅœฐๅŒ–ๆ•ฐๆฎๆณจ้‡Š

ไฝฟ็”จไบ†ๆจกๅž‹็ป‘ๅฎšๅ’Œๆ•ฐๆฎๆณจ้‡Š้ชŒ่ฏ๏ผŒไฝฟๅพ—ๆœฌๅœฐๅŒ–ๆ›ดๅŠ ๅฎนๆ˜“ใ€‚ASP.NET้‡‡็”จไบ†ไธ€ไธช็ฎ€ๅ•็š„ๅ…ฌ็บฆ๏ผŒ่ฟ™ไธชๅ…ฌ็บฆๆ˜ฏ้’ˆๅฏนๅ…ถไธญๅŒ…ๅซๆ•ฐๆฎๆณจ้‡Š้ชŒ่ฏๆถˆๆฏ็š„resx่ต„ๆบๆ–‡ไปถ๏ผš

  • ไฝไบŽ App_LocalResources ๆ–‡ไปถๅคน
  • ๆŒ‰็…ง DataAnnotation.Localization.{locale}.resx ๅ‘ฝๅ็บฆๅฎšใ€‚

ไฝฟ็”จ.NET Framework 4.6.2๏ผŒไฝ ๅฏไปฅๅœจไฝ ็š„ๆจกๅž‹ๆ–‡ไปถไธญๆŒ‡ๅฎšๆ•ฐๆฎๆณจ่งฃ๏ผŒๅฐฑๅƒไฝ ๅœจๆœชๆœฌๅœฐๅŒ–็š„ๅบ”็”จ็จ‹ๅบไธญ้‚ฃๆ ทใ€‚ๅฏนไบŽ้”™่ฏฏๆ็คบไฟกๆฏ๏ผŒๆ‚จๅฏไปฅๅœจไฝฟ็”จ็š„่ต„ๆบๆ–‡ไปถไธญๆŒ‡ๅฎšๅ็งฐ๏ผŒๅฆ‚ไธ‹ๆ‰€็คบ๏ธฐ

03

asp_net_dataAnnotation_localization

ๆ นๆฎๆ–ฐ็š„็บฆๅฎš๏ผŒไฝ ๅฏไปฅ็œ‹ๅˆฐๆœฌๅœฐๅŒ–็š„่ต„ๆบๆ–‡ไปถๅทฒ็ป่ขซๆ”พ็ฝฎๅœจโ€™App_LocalResourcesโ€™ๆ–‡ไปถๅคนไธญ๏ผŒๅฆ‚ไธ‹ๅ›พๆ‰€็คบ๏ธฐ

04

ๆ‚จไนŸๅฏไปฅๆ’ๅ…ฅ่‡ชๅทฑ็š„ stringlocalizer ๆไพ›็จ‹ๅบ๏ผŒๅฐ†ๆœฌๅœฐๅŒ–ๅญ—็ฌฆๅญ˜ๅ‚จๅœจๅฆๅค–็š„่ทฏๅพ„ๆˆ–่€…ๅฆๅค–็š„ๆ–‡ไปถ็ฑปๅž‹ใ€‚

ๅœจไน‹ๅ‰็‰ˆๆœฌ็š„.NETๆก†ๆžถไธญ๏ผŒไฝ ้œ€่ฆๆŒ‡ๅฎš ErrorMessageResourceTypeๅ’ŒErrorMessageResourceNamevalues๏ผŒๅฆ‚ไธ‹้ขๆ‰€็คบใ€‚

05

ย 

ๅผ‚ๆญฅ็š„ๆ”น่ฟ›

SessionStateModule ๅ’Œ่พ“ๅ‡บ็ผ“ๅญ˜ๆจกๅ—ๅทฒๅพ—ๅˆฐๆ”น่ฟ›๏ผŒๅฏ็”จไบ†ๅผ‚ๆญฅๅœบๆ™ฏใ€‚่ฟ™ไธชๅ›ข้˜Ÿๆญฃๅœจ้€š่ฟ‡NuGetๆฅๅ‘ๅธƒไธคไธชๆจกๅ—็š„ๅผ‚ๆญฅ็‰ˆๆœฌ๏ผŒ่ฟ™ไธช้œ€่ฆๅฏผๅ…ฅ็Žฐๆœ‰้กน็›ฎๆฅไฝฟ็”จใ€‚่ฟ™ไธคไธช NuGet ็จ‹ๅบๅŒ…้ข„่ฎกๅฐ†ๅœจๆœชๆฅๅ‡ ๅ‘จๅ‘ๅธƒใ€‚ๅฝ“ๅ‘็”Ÿ่ฟ™็งๆƒ…ๅ†ต๏ผŒๆˆ‘ไปฌๅฐ†ๆ›ดๆ–ฐ่ฟ™็ฏ‡ๆ–‡็ซ ใ€‚

ย 

SessionStateModule ๆŽฅๅฃ

ๅฝ“็”จๆˆทๅฏผ่ˆชๅˆฐASP.NET็ฝ‘็ซ™ๆ—ถ๏ผŒไผš่ฏ็Šถๆ€ๅฏไปฅๅญ˜ๅ‚จๅ’Œๆฃ€็ดข็”จๆˆทไผš่ฏๆ•ฐๆฎใ€‚็Žฐๅœจ๏ผŒ ไฝ ๅฏไปฅไฝฟ็”จๆ–ฐ็š„SessionStateModuleๆŽฅๅฃๆฅๅˆ›ๅปบ่‡ชๅทฑ็š„ๅผ‚ๆญฅไผš่ฏ็Šถๆ€ๆจกๅ—๏ผŒ่ฟ™ๆ ทไฝ ๅฐฑๅฏไปฅ็”จไฝ ่‡ชๅทฑ็š„ๆ–นๅผๆฅๅญ˜ๅ‚จไผš่ฏๆ•ฐๆฎ๏ผŒ ๅนถไธ”ไฝฟ็”จๅผ‚ๆญฅๆ–นๆณ•ใ€‚

ย 

่พ“ๅ‡บ็ผ“ๅญ˜ๆจกๅ—

่พ“ๅ‡บ็ผ“ๅญ˜้€š่ฟ‡ไปŽๆŽงๅˆถๅ™จ่กŒไธบไธญ็ผ“ๅญ˜่ฟ”ๅ›ž็ป“ๆžœ๏ผŒๅฏไปฅๆ˜พ่‘—ๅœฐๆ้ซ˜ ASP.NET ๅบ”็”จ็จ‹ๅบ็š„ๆ€ง่ƒฝ๏ผŒๅนถไธ”่ฟ™็ง็ผ“ๅญ˜ๆ–นๅผๅฏไปฅ้ฟๅ…ๅฏนไบŽๆฏไธช่ฏทๆฑ‚๏ผŒไธๅฟ…่ฆๅœฐ็”Ÿๆˆ็›ธๅŒ็š„ๅ†…ๅฎนใ€‚

็Žฐๅœจ๏ผŒ้€š่ฟ‡ๆ‰ง่กŒไธ€ไธชๅซๅšOutputCacheProviderAsync็š„ๆ–ฐๆŽฅๅฃ๏ผŒไฝ ๅฐฑๅฏไปฅๅœจ่พ“ๅ‡บ็ผ“ๅญ˜ไธญไฝฟ็”จๅผ‚ๆญฅๅบ”็”จ็จ‹ๅบๆŽฅๅฃใ€‚่ฟ™ๆ ทๅšๅฏไปฅๅ‡ๅฐ‘Web ๆœๅŠกๅ™จไธŠ็บฟ็จ‹้˜ปๅกž๏ผŒๅนถๆ้ซ˜ASP.NET ๆœๅŠก็š„ๅฏๆ‰ฉๅฑ•ๆ€งใ€‚

ย 

SQL

SQL ๅฎขๆˆท็ซฏๅ–ๅพ—ไบ†ไปฅไธ‹ๆ–น้ข็š„ๆ”น่ฟ›ใ€‚

ๅŠ ๅฏ†ๅŠŸ่ƒฝๅขžๅผบ

ๅง‹็ปˆๅŠ ๅฏ†ๅŠŸ่ƒฝๆ—จๅœจไฟๆŠคๆ•ๆ„Ÿๆ•ฐๆฎ๏ผŒไพ‹ๅฆ‚ๅญ˜ๅ‚จๅœจๆ•ฐๆฎๅบ“ไธญ็š„ไฟก็”จๅกๅท็ ๆˆ–่บซไปฝ่ฏๅท็ ใ€‚ๅฎƒๅ…่ฎธๅฎขๆˆทๅœจๅฏนๅ…ถๅบ”็”จ็จ‹ๅบๅ†…็š„ๆ•ๆ„Ÿๆ•ฐๆฎ่ฟ›่กŒๅŠ ๅฏ†๏ผŒๆฐธ่ฟœไธไผšๅฐ†ๅŠ ๅฏ†ๅฏ†้’ฅ้€้œฒ็ป™ๆ•ฐๆฎๅบ“ๅผ•ๆ“Žใ€‚ๅ› ๆญค๏ผŒๅง‹็ปˆๅŠ ๅฏ†ๅฐ†ๆ•ฐๆฎๆ‹ฅๆœ‰็€๏ผˆๅฏไปฅๆŸฅ็œ‹่ฟ™ไบ›ๆ•ฐๆฎ๏ผ‰ๅ’Œๆ•ฐๆฎ็ฎก็†่€…๏ผˆๆฒกๆœ‰ๆƒ้™ๅŽป่ฎฟ้—ฎ่ฟ™ไบ›ๆ•ฐๆฎ๏ผ‰่ฟ›่กŒไบ†ๅˆ†็ฆปใ€‚

.NET Frameworkไธญ็š„SQL Server (System.Data.SqlClient) ๆ•ฐๆฎ่ฎฟ้—ฎ็จ‹ๅบๅฏนไบŽๅง‹็ปˆๅŠ ๅฏ†ๅŠŸ่ƒฝ๏ผŒๅœจๆ€ง่ƒฝๅ’Œๅฎ‰ๅ…จๆ€งๆ–น้ขไนŸ่ฟ›่กŒไบ†ๆ”นๅ–„ใ€‚

ๆ€ง่ƒฝ

ไธบไบ†ๆ้ซ˜ๅฏนๅŠ ๅฏ†ๆ•ฐๆฎๅบ“ๅˆ—็š„ๅ‚ๆ•ฐๅŒ–ๆŸฅ่ฏขๆ€ง่ƒฝ๏ผŒๆŸฅ่ฏขๅ‚ๆ•ฐ็š„ๅ…ƒๆ•ฐๆฎ็Žฐๅœจ่ขซ็ผ“ๅญ˜ไธ‹ๆฅใ€‚ๅฝ“theSqlConnection::ColumnEncryptionQueryMetadataCacheEnabled ๅฑžๆ€ง่ฎพ็ฝฎไธบtrue๏ผˆ้ป˜่ฎคๅ€ผ๏ผ‰๏ผŒๅณไฝฟ็›ธๅŒ็š„ๆŸฅ่ฏข่ขซๅคšๆฌก่ฐƒ็”จ๏ผŒ ๅฎขๆˆท็ซฏๆ•ฐๆฎๅบ“ไนŸ้ƒฝๅชไผšไปŽๆœๅŠกๅ™จ้‡Œๆฃ€็ดขไธ€ๆฌกๅ…ƒๆ•ฐๆฎๅ‚ๆ•ฐใ€‚

ๅฎ‰ๅ…จ

ๅœจๅฏ้…็ฝฎ็š„ๆ—ถ้—ด้—ด้š”ไน‹ๅค–๏ผŒๅœจๅฏ†้’ฅ็ผ“ๅญ˜ไธญ็š„ๅˆ—ๅŠ ๅฏ†ๅฏ†้’ฅ่ฎฐๅฝ•ๅฐ†ไผš่ขซ้‡Šๆ”พใ€‚ไฝ ๅฏไปฅ้€š่ฟ‡่ฎพ็ฝฎ

SqlConnection::ColumnEncryptionKeyCacheTtl ๅฑžๆ€งๆฅ่ฎพ็ฝฎๆ—ถ้—ด้—ด้š”ใ€‚

ย 

Windows ้€šไฟกๅŸบ็ก€ (WCF)

WCF ๅšไบ†ไปฅไธ‹ๆ”น่ฟ›ใ€‚

NetNamedPipeBinding ๆœ€ไฝณๅŒน้…

ๅœจ.NET4.6.2ไธญ๏ผŒๅ…ณไบŽๆ”ฏๆŒๆ–ฐ็ฎก้“ๆŸฅๆ‰พๆฅ่ฏด๏ผŒNetNamedPipeBinding ๅทฒๅพ—ๅˆฐๅขžๅผบ๏ผŒๅฐฑๆ˜ฏๆˆ‘ไปฌๆ‰€็†Ÿ็Ÿฅโ€œๆœ€ไฝณๅŒน้…โ€ใ€‚ๅœจไฝฟ็”จ โ€œๆœ€ไฝณๅŒน้…โ€ๆ—ถ๏ผŒ่ฏฅNetNamedPipeBinding ๆœๅŠกๅฐ†ๅผบๅˆถๅฎขๆˆท็ซฏ๏ผŒๅœจๆœ€ไฝณๅŒน้…็š„URIๅ’Œ่ฏทๆฑ‚ๆ–ญ็‚นไน‹้—ดๆœ็ดขๆœๅŠกไพฆๅฌ๏ผŒ่€Œไธๆ˜ฏๆ‰พๅˆฐ็ฌฌไธ€ไธชๅŒน้…ๆœๅŠกใ€‚

ๅฆ‚ๆžœWCF ๅฎขๆˆท็ซฏๅบ”็”จ็จ‹ๅบไฝฟ็”จ้ป˜่ฎค็š„โ€้ฆ–ๅ…ˆๅŒน้…โ€่กŒไธบ๏ผŒๅฐ่ฏ•่ฟžๆŽฅๅˆฐ้”™่ฏฏ็š„ URI ๆ—ถ๏ผŒโ€ๆœ€ไฝณๅŒน้…โ€ๆ˜ฏ็‰นๅˆซๆœ‰็”จ็š„ใ€‚ๅœจๆŸไบ›ๆƒ…ๅ†ตไธ‹๏ผŒๅฝ“ๅคšไธช WCF ๆœๅŠกๅœจๆŒ‡ๅฎš็š„็ฎก้“ไธŠไพฆๅฌๆ—ถ๏ผŒWCF ๅฎขๆˆท็ซฏไฝฟ็”จโ€้ฆ–ๅ…ˆๅŒน้…โ€ๅฐ†ไผš่ฟžๆŽฅๅˆฐ้”™่ฏฏ็š„ๆœๅŠกใ€‚ๅฆ‚ๆžœไธ€ไบ›ๆœๅŠกๆ˜ฏไปฅ็ฎก็†ๅ‘˜ๅธๆˆทๆ‰˜็ฎก็š„๏ผŒ่ฟ™็งๆƒ…ๅ†ตไนŸๅฏ่ƒฝไผšๅ‘็”Ÿใ€‚

่‹ฅ่ฆๅฏ็”จๆญคๅŠŸ่ƒฝ๏ผŒไฝ ๅฏไปฅๅฐ†ไปฅไธ‹ AppSetting ๆทปๅŠ ๅˆฐๅฎขๆˆท็ซฏๅบ”็”จ็จ‹ๅบ็š„ App.config ๆˆ– Web.config ๆ–‡ไปถ๏ธฐ

06

ย 

DataContractJsonSerializer ๆ”น่ฟ›

DataContractJsonSerializer ๅทฒๅพ—ๅˆฐๆ”น่ฟ›๏ผŒไปฅๆ›ดๅฅฝๅœฐๆ”ฏๆŒๅคšไธชๅคไปคๆ—ถๅˆถ่ฐƒๆ•ด่ง„ๅˆ™ใ€‚ๅฝ“ๅฏ็”จๆ—ถ๏ผŒDataContractJsonSerializer ๅฐ†ไฝฟ็”จ TimeZoneInfo ็ฑป๏ผŒๆฅๆ›ฟไปฃๆ—ถๅŒบ็ฑปใ€‚TimeZoneInfo ็ฑปๆ”ฏๆŒๅคšไธช่ฐƒๆ•ด่ง„ๅˆ™๏ผŒ่ฟ™ไฝฟๅพ—ๅฎƒ่ƒฝๅคŸๅค„็†ๅކๅฒๆ—ถๅŒบๆ•ฐๆฎใ€‚ๅฝ“ไธ€ไธชๆ—ถๅŒบๆœ‰ไธๅŒ็š„ๅคไปคๆ—ถๅˆถ่ฐƒๆ•ด่ง„ๅˆ™ๆ—ถ๏ผˆไพ‹ๅฆ‚๏ผŒ๏ผˆUTC + 2๏ผ‰ไผŠๆ–ฏๅฆๅธƒๅฐ”๏ผ‰๏ผŒ่ฟ™ๆ˜ฏ้žๅธธๆœ‰็”จ็š„ใ€‚

ไฝ ๅฏไปฅ้€š่ฟ‡ๅ‘ app.config ๆ–‡ไปถไธญๆทปๅŠ ไปฅไธ‹ AppSetting ๅฏ็”จๆญคๅŠŸ่ƒฝ๏ธฐ

07

ย 

TransportDefaults ไธๅ†ๆ”ฏๆŒ SSL 3

ๅœจไฝฟ็”จๅŒ…ๅซ่ฟ่พ“ๅฎ‰ๅ…จๅ’Œ่ฏไนฆไฟกไปป็ฑปๅž‹็š„NetTcp่ฎพ็ฝฎๅฎ‰ๅ…จ้“พๆŽฅๆ—ถ๏ผŒSSL 3ไธๅ†ๆ˜ฏ้ป˜่ฎคๅ่ฎฎใ€‚ๅœจๅคงๅคšๆ•ฐๆƒ…ๅ†ตไธ‹๏ผŒไธไผšๅฝฑๅ“ๅˆฐ็Žฐๆœ‰็š„ๅบ”็”จ็จ‹ๅบ๏ผŒๅ› ไธบๅฏนไบŽNetTcp๏ผŒ่‡ชTLS 1.0ไปฅๆฅไธ€็›ดๅŒ…ๆ‹ฌๅœจ้ป˜่ฎคๅ่ฎฎๅˆ—่กจไธญใ€‚ๆ‰€ๆœ‰็Žฐๆœ‰็š„ๅฎขๆˆท็ซฏ่‡ณๅฐ‘่ƒฝๅคŸ้€š่ฟ‡ TLS 1.0่ฟ›่กŒ่ฟžๆŽฅใ€‚

SSL3 ไฝœไธบ้ป˜่ฎคๅ่ฎฎ่ขซ็งป้™ค๏ผŒๅ› ไธบๅฎƒไธๅ†่ขซ่ฎคไธบๆ˜ฏๅฎ‰ๅ…จ็š„ใ€‚่™ฝ็„ถไธๅปบ่ฎฎ่ฟ™ๆ ทๅš๏ผŒไฝ†ๅฆ‚ๆžœ่ฟ™ๆ˜ฏ้ƒจ็ฝฒๆ‰€ๅฟ…้œ€็š„่ฏ๏ผŒไฝ ๅฏไปฅ้€š่ฟ‡ไธ‹้ข็š„้…็ฝฎๆœบๅˆถๅฐ† SSL 3 ๅๅฎš้‡ๆ–ฐๆทปๅŠ ๅˆฐๅๅ•†้“พๆŽฅ็š„ๅˆ—่กจๅฝ“ไธญ๏ผš

ย 

Windows ๅฏ†็ ๅบ“ (CNG) ็š„ไผ ่พ“ๅฎ‰ๅ…จ

ไผ ่พ“ๅฎ‰ๅ…จ็Žฐๅœจๆ”ฏๆŒไฝฟ็”จ Windows ๅฏ†็ ๅบ“ (CNG) ๅญ˜ๅ‚จ็š„่ฏไนฆใ€‚็›ฎๅ‰๏ผŒ่ฏฅๆ”ฏๆŒไป…้™ไบŽไฝฟ็”จไธ€ไธช้•ฟๅบฆไธ่ถ…่ฟ‡ 32 ไฝๆŒ‡ๆ•ฐ็š„ๅ…ฌ้’ฅ่ฏไนฆใ€‚

่ฟ™ไธชๆ–ฐๅŠŸ่ƒฝๅœจ.NET ๆก†ๆžถ 4.6.2 ๏ผˆๆˆ–ๆ›ด้ซ˜็‰ˆๆœฌ๏ผ‰็š„ๅบ”็”จ็จ‹ๅบไธญๅฏไปฅๅฏ็”จใ€‚ๆ‚จๅฏไปฅ้€š่ฟ‡้…็ฝฎ ไปฅไธ‹ app.config ๆ–‡ไปถๆˆ– web.config ้…็ฝฎๆ–‡ไปถ๏ผŒๆฅ้…็ฝฎๅบ”็”จ็จ‹ๅบๅฎšๅ‘ๅˆฐ.NET Framework 4.6.2๏ผŒ๏ธฐ

08

ไฝ ๅฏไปฅไฝฟ็”จไธ‹้ข็š„ๆ–นๅผ่ฎพ็ฝฎAppContext๏ผŒๆฅไฝฟๅพ—ไฝ ้€‰ๆ‹ฉ็š„ไน‹ๅ‰็‰ˆๆœฌ.NET็š„ ๅบ”็”จ็จ‹ๅบๅฏไปฅไฝฟ็”จๆญค้กนๅŠŸ่ƒฝ๏ผŒ้œ€่ฆๆ้†’็š„ๆ˜ฏ๏ผŒๆญคๅผ€ๅ…ณๅช่ƒฝๅคŸไฝฟ็”จๅˆฐๅœจ.NET4.6.2๏ผˆๆˆ–ๆ›ด้ซ˜็‰ˆๆœฌ๏ผ‰ไธŠ่ฟ่กŒ็š„ๅบ”็”จ็จ‹ๅบใ€‚

09

ไฝ ไนŸๅฏไปฅไปฅ็ผ–็จ‹ๆ–นๅผๅฏ็”จๆญคๅŠŸ่ƒฝ๏ธฐ

10

ย 

OperationContext.Current ็š„ๅผ‚ๆญฅๆ”น่ฟ›

WCF ็Žฐๅœจๆœ‰่ƒฝๅŠ›ไฝฟ OperationContext.Current ๆˆไธบ ExecutionContext็š„ไธ€้ƒจๅˆ†ใ€‚้€š่ฟ‡่ฟ™ไธ€ๆ”น่ฟ›๏ผŒWCF ๅ…่ฎธ CurrentContext ไปŽไธ€ไธช็บฟ็จ‹ไผ ๆ’ญๅˆฐๅฆไธ€ไธช็บฟ็จ‹ใ€‚่ฟ™ๆ„ๅ‘ณ็€๏ผŒๅณไฝฟๅœจ่ฐƒ็”จๅˆฐ OperationContext.Current ไน‹้—ดๅญ˜ๅœจๆƒ…ๆ™ฏๅˆ‡ๆข๏ผŒๅœจๆ‰ง่กŒ็š„ๆ•ดไธชๆ–นๆณ•ไธญ๏ผŒๅฎƒ็š„ๅ€ผไนŸไผšๆญฃ็กฎไผ ้€’ใ€‚

ไธ‹้ข็š„็คบไพ‹ๆผ”็คบ OperationContext.Current ๆญฃ็กฎๆต็ป็บฟ็จ‹่ฟ‡ๆธก๏ธฐ

11

ไน‹ๅ‰๏ผŒOperationContext.Current ็š„ๅ†…้ƒจๆ‰ง่กŒๆ˜ฏไฝฟ็”จThreadStatic ๅ˜้‡ๅญ˜ๅ‚จ CurrentContext๏ผŒไฝฟ็”จ็บฟ็จ‹็š„ๆœฌๅœฐๅญ˜ๅ‚จๅŒบๆฅๅญ˜ๅ‚จไธŽ CurrentContext ็›ธๅ…ณ็š„ๆ•ฐๆฎใ€‚ๅฆ‚ๆžœๆ‰ง่กŒๆ–นๆณ•่ฐƒ็”จ็š„ๅœบๆ™ฏๅ‘็”Ÿๆ”นๅ˜๏ผˆๅณ๏ผŒ็”ฑ็ญ‰ๅพ…ๅ…ถไป–ๆ“ไฝœ็š„็บฟ็จ‹ๆ›ดๆ”น๏ผ‰๏ผŒไปปไฝ•ไน‹ๅŽ็š„่ฐƒ็”จๅฐ†่ฟ่กŒๅœจไธๅŒ็š„็บฟ็จ‹๏ผŒ่€ŒๅฏนๅŽŸๅง‹ๅ€ผๆฒกๆœ‰ๅผ•็”จใ€‚็ป่ฟ‡่ฟ™ๆ ท็š„ไฟฎๅคไน‹ๅŽ๏ผŒ็ฌฌไบŒๆฌก่ฐƒ็”จ็š„OperationContext.Currentไผš่Žทๅ–้ข„ๆœŸ็š„ๅ€ผ๏ผŒๅฐฝ็ฎก threadId1 ๅ’Œ threadId2 ๅฏ่ƒฝไผšๆœ‰ๆ‰€ไธๅŒใ€‚

ย 

Windows Presentation Foundation (WPF)

WPFๅšไบ†ๅฆ‚ไธ‹ๆ”น่ฟ›๏ผš

ๅˆ†็ป„ๆŽ’ๅบ

็Žฐๅœจ๏ผŒไฝฟ็”จCollectionView ๅฏนๆ•ฐๆฎๆŽ’ๅบ็š„ๅบ”็”จ็จ‹ๅบๅฏไปฅๆ˜Ž็กฎๅœฐๅฃฐๆ˜Žๅฆ‚ไฝ•่ฟ›่กŒ็ป„ๆŽ’ๅบใ€‚่ฟ™ๅ…‹ๆœไบ†ๅฝ“ๅบ”็”จ็จ‹ๅบๅŠจๆ€ๅœฐๆทปๅŠ ๆˆ–ๅˆ ้™ค็ป„๏ผŒๆˆ–่€…ๆ˜ฏๅบ”็”จ็จ‹ๅบๆ›ดๆ”นๅ‚ไธŽๅˆ†็ป„็š„้กน็›ฎๅฑžๆ€งๅ€ผๆ—ถไธ€ไบ›ๅฏ่ƒฝไผšๅ‡บ็Žฐ็š„ไธ็›ด่ง‚็š„ๆŽ’ๅบใ€‚้€š่ฟ‡ๆฏ”่พƒๅˆ†็ป„ไธญ็š„ๆ•ฐๆฎๆฅๆŽ’ๅบ๏ผŒ่€Œไธๆ˜ฏๆ•ดไธช้›†ๅˆ็š„ๆ•ฐๆฎ๏ผŒ่ฟ™ไนŸๆ้ซ˜ไบ†ๅˆ›ๅปบ็ป„็š„ๆ€ง่ƒฝใ€‚

่ฏฅๅŠŸ่ƒฝๅŒ…ๆ‹ฌGroupDescription ็ฑป็š„ไธคไธชๆ–ฐๅฑžๆ€ง๏ธฐ SortDescriptions ๅ’Œ CustomSortใ€‚่ฟ™ไบ›ๅฑžๆ€งๆ่ฟฐไบ†ๅฆ‚ไฝ•ๅฏนไฝฟ็”จGroupDescriptionไบง็”Ÿ็š„็ป„้›†ๅˆ่ฟ›่กŒๆŽ’ๅบ๏ผŒๅœจ ListCollectionViewไธญ๏ผŒไนŸๆœ‰ไธŽไน‹ๅŒๅ็š„ๅฑžๆ€งๆ่ฟฐๅฆ‚ไฝ•ๅฏนๆ•ฐๆฎ้กน็›ฎ่ฟ›่กŒๆŽ’ๅบใ€‚ๅœจ PropertyGroupDescription ็ฑป้‡Œ้ขๆœ‰ไธคไธชๆ–ฐ็š„้™ๆ€ๅฑžๆ€ง๏ผŒไฝฟ็”จๆœ€ไธบๅธธ่ง็š„ไธคไธชๆ–ฐ็š„้™ๆ€ๅฑžๆ€ง๏ธฐ CompareNameAscendingๅ’Œ CompareNameDescendingใ€‚

ไพ‹ๅฆ‚๏ผŒๅ‡่ฎพๅบ”็”จ็จ‹ๅบๆƒณ่ฆๆŒ‰ๅนด้พ„ๅˆ†็ป„๏ผŒ่ฟ›่กŒๅ‡ๅบๆŽ’ๅˆ—๏ผŒๆฏไธช็ป„ๆŒ‰็…งๅง“ๆฐๆŽ’ๅบใ€‚

ๅบ”็”จ็จ‹ๅบ็Žฐๅœจๅฏไปฅไฝฟ็”จๆญคๆ–ฐๅŠŸ่ƒฝ็š„ๅฃฐๆ˜Ž๏ธฐ

12

่ฟ™ไธชๆ–ฐๅŠŸ่ƒฝไน‹ๅ‰๏ผŒๅบ”็”จ็จ‹ๅบไผšๅฆ‚ไธ‹ๅฃฐๆ˜Ž๏ธฐ

13

ย 

ๆ”ฏๆŒๅŒๆ—ถๅœจไธๅŒๅˆ†่พจ็އ็š„ๆ˜พ็คบๅ™จไธŠๆ˜พ็คบ

WPF ๅบ”็”จ็จ‹ๅบ็Žฐๅœจๅฏ็”จๆฏไธชๆ˜พ็คบๅ™จๅˆ†่พจ็އ่ฎค็Ÿฅใ€‚่ฟ™ไธชๆ”น่ฟ›ๅฏนไบŽไธๅŒๅˆ†่พจ็އ็บงๅˆซ็š„ๅคšไธชๅฑๅน•่ฟžๆŽฅๅœจไธ€ๅฐๆœบๅ™จไธŠ็š„ๆ˜พ็คบ่‡ณๅ…ณ้‡่ฆใ€‚ๅœจๅœบๆ™ฏไธๅŒ DPI ็บงๅˆซ็š„ๅคšๅฐๆ˜พ็คบๅ™จ็›ธ่ฟžไธบไธ€ๅฐๆœบๅ™จใ€‚็”ฑไบŽWPF ๅบ”็”จ็จ‹ๅบ็š„ๅ…จ้ƒจๆˆ–้ƒจๅˆ†ๅ†…ๅฎนไผšๅœจๅคšไธชๆ˜พ็คบๅ™จไธŠๆ˜พ็คบ๏ผŒๆˆ‘ไปฌๆœŸๆœ› WPF่ƒฝๅคŸ่‡ชๅŠจๅฐ†ๅบ”็”จ็จ‹ๅบ็š„ๅˆ†่พจ็އๅ’Œๅฑๅน•่ฟ›่กŒๅŒน้…๏ผŒ็Žฐๅœจๅฎƒ็œŸ็š„ๅšๅˆฐไบ†ใ€‚

ๆ‚จๅฏไปฅๅœจWPF ๅฎžไพ‹ๅ’Œๅœจ GitHub ไธŠ็š„ๅผ€ๅ‘ไบบๅ‘˜ๆŒ‡ๅ— ไธญไบ†่งฃๆ›ดๅคšๆœ‰ๅ…ณๅฆ‚ไฝ•ๅฏ็”จๆ‚จ็š„ WPF ๅบ”็”จ็จ‹ๅบๅฏนๆฏไธชๅฑๅน•ๅˆ†่พจ็އ้€‚ๅบ”ๅŠŸ่ƒฝ ใ€‚

ๅœจไปฅๅ‰็š„็‰ˆๆœฌ๏ผŒไฝ ๅฟ…้กป็ผ–ๅ†™้ขๅค–็š„ไปฃ็ ๏ผŒๆฅๅฏ็”จWPF ๅบ”็”จ็จ‹ๅบไธญๆฏไธชๆ˜พ็คบๅ™จ ๅˆ†่พจ็އ็š„่ฎค็Ÿฅใ€‚

ย 

ๆ”ฏๆŒ่ฝฏ้”ฎ็›˜

่ฝฏ้”ฎ็›˜ๆ”ฏๆŒ่ƒฝๅคŸ่‡ชๅŠจ่ฐƒ็”จๅ’Œ่งฃ้™คWPF ๅบ”็”จ็จ‹ๅบไธญ็š„่งฆๆ‘ธ้”ฎ็›˜๏ผŒ่€ŒไธไผšๅœจWin10ๆ“ไฝœ็ณป็ปŸไธญ็ฆ็”จ WPF ๆ‰‹ๅ†™/่งฆๆŽงๆ”ฏๆŒใ€‚

ไปฅๅ‰็š„็‰ˆๆœฌ้‡Œ๏ผŒๅœจไธ็ฆ็”จ WPF ๆ‰‹ๅ†™/่งฆๆŽงๆ”ฏๆŒ็š„ๆƒ…ๅ†ตไธ‹๏ผŒWPF ๅบ”็”จ็จ‹ๅบๅฐ†ไธไผšๆ”ฏๆŒ่ฐƒ็”จๆˆ–่งฃ้™ค่งฆๆ‘ธ้”ฎ็›˜ใ€‚่ฟ™ๆ˜ฏ็”ฑไบŽไปŽWin8ๆ“ไฝœ็ณป็ปŸๅผ€ๅง‹๏ผŒๅบ”็”จ็จ‹ๅบไธญ่ฟฝ่ธช่งฆๆ‘ธ้”ฎ็›˜็„ฆ็‚น็š„ๆ–นๅผๅ‘็”Ÿไบ†ๆ”นๅ˜ใ€‚

softkeyboard

ย 

ๆ‚จ็š„ๅ้ฆˆ

ๆœ€ๅŽ๏ผŒๆˆ‘ๆƒณๅ†ๆฌกๆ„Ÿ่ฐขไธ‹้‚ฃไบ›ไธบ 4.6.2 ้ข„่งˆ็‰ˆๆœฌๆไพ›ๅ้ฆˆ็š„ไบบ๏ผๅฎƒๆœ‰ๅŠฉไบŽ4.6.2 ็š„ๅ‘ๅธƒใ€‚่ฏทๆ‚จ็ปง็ปญ้€š่ฟ‡ไปฅไธ‹ๆ–นๅผๆๅ‡บๅ้ฆˆๆ„่ง๏ธฐ

โ†ง

Microsoft Graph โ€“ OneDrive API (C#) ใ‚’ไฝฟใฃใŸใ‚ตใƒณใƒ—ใƒซ ใ‚ณใƒผใƒ‰

$
0
0

ใ“ใ‚“ใซใกใฏใ€Office Developerย ใ‚ตใƒใƒผใƒˆใฎๆฃฎใ€€ๅฅๅพ (kenmori) ใงใ™ใ€‚

ไปŠๅ›žใฎๆŠ•็จฟใงใฏใ€Microsoft Graph โ€“ OneDrive API ใ‚’ๅฎŸ้š›ใซ C# ใง้–‹็™บใ™ใ‚‹ใ‚จใ‚ฏใ‚นใƒšใƒชใ‚จใƒณใ‚นใ‚’ใ”็ดนไป‹ใ—ใพใ™ใ€‚

ใ‚ฆใ‚ฉใƒผใ‚ฏใ‚นใƒซใƒผใฎใ‚ˆใ†ใชๅฝขๅผใซใ—ใฆใŠใ‚Šใพใ™ใฎใงใ€ๆ…ฃใ‚Œใฆใ„ใชใ„ๆ–นใ‚‚ไปŠๅ›žใฎๆŠ•็จฟใ‚’ไธ€้€šใ‚ŠๅฎŸๆ–ฝใ™ใ‚‹ใ“ใจใงใ€ใƒ—ใƒญใ‚ฐใƒฉใƒ ้–‹็™บใ‚’็ตŒ้จ“ใ—็†่งฃใงใใ‚‹ใจๆ€ใ„ใพใ™ใ€‚ๆœฌๆŠ•็จฟใงใฏใ€็พๅฎŸ็š„ใชๅฎŸ่ฃ…ใ‚ทใƒŠใƒชใ‚ชใ‚’้‡่ฆ–ใ™ใ‚‹ใ‚ˆใ‚Šใ‚‚ใ€OneDrive API ใ‚’็†่งฃใ™ใ‚‹ใŸใ‚ใซใชใ‚‹ในใใ‚ทใƒณใƒ—ใƒซใชใ‚ณใƒผใƒ‰ใซใ™ใ‚‹ใ“ใจใ‚’ๅฟƒๆŽ›ใ‘ใฆใ„ใพใ™ใ€‚

ไพ‹ๅค–ๅ‡ฆ็†ใชใฉใ‚‚ๅซใ‚ใฆใ„ใพใ›ใ‚“ใฎใงใ€ๅฎŸ้š›ใซใ‚ณใƒผใƒ‡ใ‚ฃใƒณใ‚ฐใ™ใ‚‹้š›ใซใฏใ€ใ‚ใใพใงใ“ใฎใ‚ณใƒผใƒ‰ใ‚’ๅ‚่€ƒใ™ใ‚‹ๅฝขใงใ”ๆคœ่จŽใใ ใ•ใ„ใ€‚

ย 

ไบ‹ๅ‰ๆบ–ๅ‚™

ไปฅๅ‰ใฎๆŠ•็จฟใ‚’ใ‚‚ใจใซใ€Azure AD ใซใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎ็™ป้Œฒใ‚’ๅฎŒไบ†ใ—ใฆใใ ใ•ใ„ใ€‚ๅฐ‘ใชใใจใ‚‚ไปฅไธ‹ใฎ 2 ใคใฎใƒ‡ใƒชใ‚ฒใƒผใƒˆใ•ใ‚ŒใŸใ‚ขใ‚ฏใ‚ปใ‚น่จฑๅฏใŒๅฟ…่ฆใงใ™ใ€‚

ใƒปHave full access to all files user can access
ใƒปSign users in

ใใฎไธŠใงใ€ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆ ID ใจใƒชใƒ€ใ‚คใƒฌใ‚ฏใƒˆ URI ใ‚’ๆŽงใˆใฆใŠใ„ใฆใใ ใ•ใ„ใ€‚

ย 

้–‹็™บๆ‰‹้ †

1. Visual Studio ใ‚’่ตทๅ‹•ใ—ใ€Windows ใƒ•ใ‚ฉใƒผใƒ  ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚’้–‹ๅง‹ใ—ใพใ™ใ€‚
2. ใ‚ฝใƒชใƒฅใƒผใ‚ทใƒงใƒณ ใ‚จใ‚ฏใ‚นใƒ—ใƒญใƒผใƒฉใซใฆ [ๅ‚็…ง] ใ‚’ๅณใ‚ฏใƒชใƒƒใ‚ฏใ—ใ€[NuGet ใƒ‘ใƒƒใ‚ฑใƒผใ‚ธใฎ็ฎก็†] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใพใ™ใ€‚

odapi1

3. ADAL ใงๆคœ็ดขใ—ใ€Microsoft.IdentityMode.Clients.ActiveDirectory ใ‚’ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใพใ™ใ€‚

odapi2

4. [OK] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใ€[ๅŒๆ„ใ™ใ‚‹] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใพใ™ใ€‚
5. ๆฌกใซๅŒๆง˜ใฎๆ“ไฝœใง Newtonsoft ใงๆคœ็ดขใ—ใ€Newtonsoft.Json ใ‚’ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใพใ™ใ€‚
6. ๆฌกใซใƒ•ใ‚ฉใƒผใƒ ใ‚’ใƒ‡ใ‚ถใ‚คใƒณใ—ใพใ™ใ€‚

odapi3

ใ‚ณใƒณใƒˆใƒญใƒผใƒซไธ€่ฆง

  • OneDriveTestForm ใƒ•ใ‚ฉใƒผใƒ 
  • fileListLB ใƒชใ‚นใƒˆ ใƒœใƒƒใ‚ฏใ‚น
  • fileNameTB ใƒ†ใ‚ญใ‚นใƒˆ ใƒœใƒƒใ‚ฏใ‚น
  • uploadBtn ใƒœใ‚ฟใƒณ
  • renameBtn ใƒœใ‚ฟใƒณ
  • deleteBtn ใƒœใ‚ฟใƒณ
  • openFileDialog1 ใ‚ชใƒผใƒ—ใƒณ ใƒ•ใ‚กใ‚คใƒซ ใƒ€ใ‚คใ‚ขใƒญใ‚ฐ

ย 

7. ใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใ‚’ๅณใ‚ฏใƒชใƒƒใ‚ฏใ—ใ€[่ฟฝๅŠ ] โ€“ [ๆ–ฐใ—ใ„้ …็›ฎ] ใ‚’ใ‚ฏใƒชใƒƒใ‚ฏใ—ใพใ™ใ€‚
8. MyFile.cs ใ‚’่ฟฝๅŠ ใ—ใพใ™ใ€‚
9. ไปฅไธ‹ใฎใ‚ˆใ†ใชๅฎš็พฉ (JSON ๅค‰ๆ›็”จ) ใ‚’่จ˜่ผ‰ใ—ใพใ™ใ€‚
ย โ€ป ไปŠๅ›žใฎใ‚ตใƒณใƒ—ใƒซใงใฏไฝฟ็”จใ—ใชใ„ๅฎš็พฉใ‚‚ๆฎ‹ใ—ใฆใ„ใพใ™ใ€‚ใ‚ณใƒผใƒ‰ใ‚’ๆ›ธใๆ›ใˆใฆใƒ‡ใƒผใ‚ฟใ‚’ๅ‚็…งใ—ใŸใ‚Šใ€ๅค‰ๆ›ดใ™ใ‚‹ใชใฉใ—ใฆใฟใฆใใ ใ•ใ„ใ€‚

using Newtonsoft.Json;
using System.Collections.Generic;

namespace OneDriveDemo
{
ย ย ย  public class MyFile
ย ย ย  {
ย ย ย ย ย ย ย  public string name { get; set; }
ย ย ย ย ย ย  ย // ไปฅไธ‹ใฎใƒ—ใƒญใƒ‘ใƒ†ใ‚ฃใฏไปŠๅ›žไฝฟ็”จใ—ใพใ›ใ‚“ใŒใ€ใƒ‡ใƒใƒƒใ‚ฐๆ™‚ใซๅ€คใ‚’่ฆ‹ใ‚‹ใ“ใจใ‚’ใŠๅ‹งใ‚ใ—ใพใ™ใ€‚
ย ย ย ย ย ย ย  public string webUrl { get; set; }
ย ย ย ย ย ย ย  public string createdDateTime { get; set; }
ย ย ย ย ย ย ย  public string lastModifiedDateTime { get; set; }
ย ย ย  }

ย ย ย  public class MyFiles
ย ย ย  {
ย ย ย ย ย ย ย  public List<MyFile> value;
ย ย ย  }

ย ย  ย // ใƒ•ใ‚กใ‚คใƒซ็งปๅ‹•ๆ™‚ใซไฝฟใ„ใพใ™ใ€‚
ย ย ย  public class MyParentFolder
ย ย ย  {
ย ย ย ย ย ย ย  public string path { get; set; }
ย ย ย  }

 ย ย  public class MyFileModify
ย ย ย  {
ย ย ย ย ย ย ย  public string name { get; set; }
ย ย ย ย ย ย  ย // ใƒ•ใ‚กใ‚คใƒซ็งปๅ‹•ๆ™‚ใซไฝฟใ„ใพใ™ใ€‚
ย ย ย ย ย ย ย  public MyParentFolder parentReference { get; set; }
ย ย ย  }
}

่ฃœ่ถณ
JSON ๅค‰ๆ›ๆ™‚ใซใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆ ใƒ—ใƒญใƒ‘ใƒ†ใ‚ฃๅดใซๅˆฅๅใ‚’ไป˜ใ‘ใŸใ„ๅ ดๅˆใฏใ€ไธ‹่จ˜ใฎใ‚ˆใ†ใซ JsonProperty ๅฑžๆ€งใ‚’ๆŒ‡ๅฎšใ™ใ‚‹ใ“ใจใงๅฏ่ƒฝใงใ™ใ€‚

[JsonProperty("name")]
public string FileName { get; set; }

10. ใƒ•ใ‚ฉใƒผใƒ ใฎใ‚ณใƒผใƒ‰ใซ็งปๅ‹•ใ—ใพใ™ใ€‚
11. using ใ‚’่ฟฝ่จ˜ใ—ใฆใŠใใพใ™ใ€‚

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

12. ใƒ•ใ‚ฉใƒผใƒ ใฎใƒกใƒณใƒใƒผๅค‰ๆ•ฐใซไปฅไธ‹ใ‚’ๅŠ ใˆใพใ™ใ€‚
ย โ€ป clientid ใ‚„ redirecturi ใฏ Azure AD ใงไบ‹ๅ‰ใซ็™ป้Œฒใ—ใŸใ‚‚ใฎใ‚’ไฝฟ็”จใใ ใ•ใ„ใ€‚

ย ย ย ย ย ย ย  const string resource = "https://graph.microsoft.com";
ย ย ย ย ย ย ย  const string clientid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
ย ย ย ย ย ย ย  const string redirecturi = "urn:getaccesstokenfordebug";
ย ย ย ย ย ย ย  // ADFS ็’ฐๅขƒใง SSO ใƒ‰ใƒกใ‚คใƒณไปฅๅค–ใฎใƒ†ใƒŠใƒณใƒˆใฎใƒฆใƒผใ‚ถใƒผใ‚’่ฉฆใ™ๅ ดๅˆใฏใ‚ณใƒกใƒณใƒˆ่งฃ้™ค
ย ย ย ย ย ย ย  // const string loginname = "admin@tenant.onmicrosoft.com";

ย ย ย ย ย ย ย  string AccessToken;

13. ใƒ•ใ‚ฉใƒผใƒ ใฎใƒ‡ใ‚ถใ‚คใƒณใงใƒ•ใ‚ฉใƒผใƒ ใ‚’ใƒ€ใƒ–ใƒซใ‚ฏใƒชใƒƒใ‚ฏใ—ใ€ใƒญใƒผใƒ‰ๆ™‚ใฎใ‚คใƒ™ใƒณใƒˆใ‚’ๅฎŸ่ฃ…ใ—ใพใ™ใ€‚

ย ย ย ย ย ย ย  private async void Form1_Load(object sender, EventArgs e)
ย  ย  ย  ย  {
ย ย ย ย ย ย ย ย ย ย ย  AccessToken = await GetAccessToken(resource, clientid, redirecturi);
ย ย ย ย ย ย ย ย ย ย ย  DisplayFiles();
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย  ย // ใ‚ขใ‚ฏใ‚ปใ‚น ใƒˆใƒผใ‚ฏใƒณๅ–ๅพ—
ย ย ย ย ย ย ย  private async Task<string> GetAccessToken(string resource, string clientid, string redirecturi)
ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย  AuthenticationContext authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/common");
ย ย ย ย ย ย ย ย ย ย ย  AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  resource,
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  clientid,
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  new Uri(redirecturi),
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  new PlatformParameters(PromptBehavior.Auto, null)
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  // ADFS ็’ฐๅขƒใง SSO ใƒ‰ใƒกใ‚คใƒณไปฅๅค–ใฎใƒ†ใƒŠใƒณใƒˆใฎใƒฆใƒผใ‚ถใƒผใ‚’่ฉฆใ™ๅ ดๅˆใฏใ‚ณใƒกใƒณใƒˆ่งฃ้™ค
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  //, new UserIdentifier(loginname, UserIdentifierType.RequiredDisplayableId)ย ย ย ย ย ย ย ย ย ย ย  );
ย ย ย ย ย ย ย ย ย ย ย  return authenticationResult.AccessToken;
ย ย ย ย ย ย ย  }

 ย ย ย ย ย  ย // ใƒ•ใ‚กใ‚คใƒซไธ€่ฆง่กจ็คบ
ย ย ย ย ย ย ย  private async void DisplayFiles()
ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย  using (HttpClient httpClient = new HttpClient())
ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  HttpRequestMessage request = new HttpRequestMessage(
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  HttpMethod.Get,
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  new Uri("https://graph.microsoft.com/v1.0/me/drive/root/children?$select=name,weburl,createdDateTime,lastModifiedDateTime")
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  );
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  var response = await httpClient.SendAsync(request);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  MyFiles files = JsonConvert.DeserializeObject<MyFiles>(response.Content.ReadAsStringAsync().Result);

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  fileListLB.Items.Clear();
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  foreach (MyFile file in files.value)
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  fileListLB.Items.Add(file.name);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  if (!string.IsNullOrEmpty(fileNameTB.Text))
ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  fileListLB.SelectedItem = fileNameTB.Text;
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย  ย ย ย ย ย }

14. fileListLB ใฎ SelectedIndexChanged ใ‚คใƒ™ใƒณใƒˆใ‚’ใƒ€ใƒ–ใƒซใ‚ฏใƒชใƒƒใ‚ฏใ—ใฆใ€ๅ‡ฆ็†ใ‚’ๅฎŸ่ฃ…ใ—ใพใ™ใ€‚

ย ย ย ย ย ย ย  // ใƒชใ‚นใƒˆ ใƒœใƒƒใ‚ฏใ‚นใง้ธๆŠžใ—ใŸใƒ•ใ‚กใ‚คใƒซใ‚’ใƒ†ใ‚ญใ‚นใƒˆ ใƒœใƒƒใ‚ฏใ‚นใซๅŒๆœŸ
ย ย ย ย ย ย ย  private void fileListLB_SelectedIndexChanged(object sender, EventArgs e)
ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย  fileNameTB.Text = ((ListBox)sender).SelectedItem.ToString();
ย ย ย ย ย ย ย  }

15. uploadBtn ใ‚’ใƒ€ใƒ–ใƒซใ‚ฏใƒชใƒƒใ‚ฏใ—ใฆใ€ใƒœใ‚ฟใƒณใ‚ฏใƒชใƒƒใ‚ฏใ‚คใƒ™ใƒณใƒˆใ‚’ๅฎŸ่ฃ…ใ—ใพใ™ใ€‚
โ€ป ใ“ใฎๆ–นๅผใงใ‚ขใƒƒใƒ—ใƒญใƒผใƒ‰ใงใใ‚‹ใƒ•ใ‚กใ‚คใƒซ ใ‚ตใ‚คใ‚บใซใฏๅˆถ้™ใŒใ‚ใ‚Šใพใ™ใ€‚

  ย ย ย ย  ย // ใƒ•ใ‚กใ‚คใƒซ ใ‚ขใƒƒใƒ—ใƒญใƒผใƒ‰ๅ‡ฆ็†
ย ย ย ย ย ย ย  private async void uploadBtn_Click(object sender, EventArgs e)
ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย  if (openFileDialog1.ShowDialog() == DialogResult.OK)
ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  fileNameTB.Text = openFileDialog1.FileName.Substring(openFileDialog1.FileName.LastIndexOf("\") + 1);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  using (HttpClient httpClient = new HttpClient())
ย ย ย ย ย ย  ย ย ย ย ย ย ย ย ย {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "octet-stream");
ย ย ย ย ย ย ย ย ย ย  ย ย ย ย ย ย ย ย ย HttpRequestMessage request = new HttpRequestMessage(
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  HttpMethod.Put,
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  new Uri(string.Format("https://graph.microsoft.com/v1.0/me/drive/root:/{0}:/content", fileNameTB.Text))
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  );
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  request.Content = new ByteArrayContent(ReadFileContent(openFileDialog1.FileName));
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  var response = await httpClient.SendAsync(request);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  MessageBox.Show(response.StatusCode.ToString());
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  DisplayFiles();
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย  ย // ใƒญใƒผใ‚ซใƒซ ใƒ•ใ‚กใ‚คใƒซใฎ่ชญใฟๅ–ใ‚Šๅ‡ฆ็†
ย ย ย ย ย ย ย  private byte[] ReadFileContent(string filePath)
ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย  using (FileStream inStrm = new FileStream(filePath, FileMode.Open))
ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  byte[] buf = new byte[2048];
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  using (MemoryStream memoryStream = new MemoryStream())
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  int readBytes = inStrm.Read(buf, 0, buf.Length);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  while (readBytes > 0)
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  memoryStream.Write(buf, 0, readBytes);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  readBytes = inStrm.Read(buf, 0, buf.Length);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return memoryStream.ToArray();
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  ย ย ย ย }
ย ย ย ย ย ย ย  }

16. renameBtn ใ‚’ใƒ€ใƒ–ใƒซใ‚ฏใƒชใƒƒใ‚ฏใ—ใฆใ€ใ‚ฏใƒชใƒƒใ‚ฏใ‚คใƒ™ใƒณใƒˆใ‚’ๅฎŸ่ฃ…ใ—ใพใ™ใ€‚

ย ย ย ย ย ย  ย // ใƒ•ใ‚กใ‚คใƒซๅใฎๅค‰ๆ›ดๅ‡ฆ็†
ย ย ย ย ย ย ย  private async void renameBtn_Click(object sender, EventArgs e)
ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย  foreach (string fileLeafRef in fileListLB.SelectedItems)
ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  using (HttpClient httpClient = new HttpClient())
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  HttpRequestMessage request = new HttpRequestMessage(
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  new HttpMethod("PATCH"),
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  new Uri(string.Format("https://graph.microsoft.com/v1.0/me/drive/root:/{0}", fileLeafRef))
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  );

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  MyFileModify filemod = new MyFileModify();
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  filemod.name = fileNameTB.Text;
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  request.Content = new StringContent(JsonConvert.SerializeObject(filemod), Encoding.UTF8, "application/json");

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  var response = await httpClient.SendAsync(request);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  MessageBox.Show(response.StatusCode.ToString());
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  DisplayFiles();
ย ย ย ย ย ย ย  }

17. deleteBtn ใ‚’ใƒ€ใƒ–ใƒซใ‚ฏใƒชใƒƒใ‚ฏใ—ใฆใ€ใ‚ฏใƒชใƒƒใ‚ฏใ‚คใƒ™ใƒณใƒˆใ‚’ๅฎŸ่ฃ…ใ—ใพใ™ใ€‚

ย ย ย ย ย ย  ย // ใƒ•ใ‚กใ‚คใƒซๅ‰Š้™คๅ‡ฆ็†
ย ย ย ย ย ย ย  private async void deleteBtn_Click(object sender, EventArgs e)
ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย  foreach (string fileLeafRef in fileListLB.SelectedItems)
ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  using (HttpClient httpClient = new HttpClient())
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  HttpRequestMessage request = new HttpRequestMessage(
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  HttpMethod.Delete,
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  new Uri(string.Format("https://graph.microsoft.com/v1.0/me/drive/root:/{0}", fileLeafRef))
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  );
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  var response = await httpClient.SendAsync(request);
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  MessageBox.Show(response.StatusCode.ToString());
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  fileNameTB.Text = "";
ย ย ย ย ย ย ย ย ย ย ย  DisplayFiles();
ย ย ย ย ย ย ย  }

18. ใ‚ฝใƒชใƒฅใƒผใ‚ทใƒงใƒณใ‚’ใƒ“ใƒซใƒ‰ใ—ใฆใ€ๅ‹•ไฝœใ‚’็ขบ่ชใ—ใพใ—ใ‚‡ใ†ใ€‚

ย ๆœ€ๅˆใซใƒญใ‚ฐใ‚คใƒณ็”ป้ขใŒ่กจ็คบใ•ใ‚Œใ€ใƒญใ‚ฐใ‚คใƒณใ—ใŸใƒฆใƒผใ‚ถใƒผใงใ‚ขใ‚ฏใ‚ปใ‚น ใƒˆใƒผใ‚ฏใƒณใ‚’ๅ–ๅพ—ใ—ใพใ™ใ€‚
โ€ป ใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชๅŒๆœŸใ•ใ‚ŒใŸใƒ‰ใƒกใ‚คใƒณใงใƒ€ใ‚คใ‚ขใƒญใ‚ฐใ‚’่กจ็คบใ™ใ‚‹ใจใ€ใƒฆใƒผใ‚ถใƒผๅใƒปใƒ‘ใ‚นใƒฏใƒผใƒ‰ใฎๅ…ฅๅŠ›็”ป้ขใŒ่กจ็คบใ•ใ‚Œใšใ€่‡ชๅ‹•็š„ใซใƒญใ‚ฐใ‚คใƒณใ•ใ‚Œใ‚‹ๅ ดๅˆใŒใ‚ใ‚Šใพใ™ใ€‚

odapi4

่ฉฒๅฝ“ใƒฆใƒผใ‚ถใƒผใฎ OneDrive for Business ใฎใƒซใƒผใƒˆ ใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชใฎใƒ•ใ‚กใ‚คใƒซไธ€่ฆงใŒ่กจ็คบใ•ใ‚Œใพใ™ใ€‚

odapi5

่ฉฒๅฝ“ใƒ•ใ‚ฉใƒซใƒ€ใƒผใงใ€ใƒ•ใ‚กใ‚คใƒซใฎใ‚ขใƒƒใƒ—ใƒญใƒผใƒ‰ใ‚„ๅๅ‰ๅค‰ๆ›ดใ€ๅ‰Š้™คใชใฉใฎๆ“ไฝœใ‚’ใŠ่ฉฆใ—ใใ ใ•ใ„ใ€‚

ย 

ๅ‚่€ƒๆƒ…ๅ ฑ

ไปฅไธ‹ใฏใ€Microsoft Graph ใซใŠใ‘ใ‚‹ OneDrive API ใฎๅ‚่€ƒใ‚ตใ‚คใƒˆใงใ™ใ€‚

ใ‚ฟใ‚คใƒˆใƒซ : OneDrive API Documentation in Microsoft Graph
ใ‚ขใƒ‰ใƒฌใ‚น : https://graph.microsoft.io/en-us/docs/api-reference/v1.0/resources/drive

OneDrive API ใฎใƒชใƒ•ใ‚กใƒฌใƒณใ‚นใซใคใ„ใฆใฏใ€ไปฅไธ‹ใฎใƒšใƒผใ‚ธใ‚’ใ”็ขบ่ชใ„ใŸใ ใใ€OneDrive APIใŒๆŒใคๆง˜ใ€…ใชใƒกใ‚ฝใƒƒใƒ‰ใ‚’ใŠ่ฉฆใ—ใใ ใ•ใ„ใ€‚

ใ‚ฟใ‚คใƒˆใƒซ : Develop with the OneDrive API
ใ‚ขใƒ‰ใƒฌใ‚น : https://dev.onedrive.com/README.htm#

็พๆ™‚็‚นใงใฏใ€OneDrive API ใงๅฎŸ่ฃ…ใงใใ‚‹็ฏ„ๅ›ฒใซใคใ„ใฆใ€OneDrive ใ‚ณใƒณใ‚ทใƒฅใƒผใƒž็‰ˆใจ OneDrive for Business ใซใฏ็›ธ้•ใŒใ‚ใ‚Šใพใ™ใ€‚่ฉณ็ดฐใฏไปฅไธ‹ใ‚’ใ”็ขบ่ชใใ ใ•ใ„ใ€‚

ใ‚ฟใ‚คใƒˆใƒซ : Release notes for using OneDrive API with OneDrive for Business and SharePoint
ใ‚ขใƒ‰ใƒฌใ‚น : https://dev.onedrive.com/sharepoint/release-notes.htm

ไปฅไธ‹ใฏใ€OneDrive API ใ‚’็ดนไป‹ใ—ใŸ Channel9 ใฎๅ‹•็”ปใซใชใ‚Šใพใ™ใ€‚

ใ‚ฟใ‚คใƒˆใƒซ : Office Dev Show โ€“ Episode 38 โ€“ OneDrive APIs in the Microsoftย Graph
ใ‚ขใƒ‰ใƒฌใ‚น : https://channel9.msdn.com/Shows/Office-Dev-Show/Office-Dev-Show-Episode-38-OneDrive-APIs-in-the-Microsoft-Graph

Json.NET ใซ้–ขใ™ใ‚‹ใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใฏไปฅไธ‹ใ‚’ใ”ๅ‚่€ƒใซใ—ใฆใใ ใ•ใ„ใ€‚

ใ‚ฟใ‚คใƒˆใƒซ : Json.NET Documentation
ใ‚ขใƒ‰ใƒฌใ‚น : http://www.newtonsoft.com/json/help/html/Introduction.htm

ใ‚ฟใ‚คใƒˆใƒซ : Serializing and Deserializing JSON
ใ‚ขใƒ‰ใƒฌใ‚น : http://www.newtonsoft.com/json/help/html/SerializingJSON.htm

ๅˆฅๆŠ•็จฟใซ่จ˜่ผ‰ใ—ใŸ้€šใ‚Šใ€้–‹็™บๅทฅๆ•ฐๅ‰Šๆธ›ใฎใŸใ‚ใ€ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณ้–‹็™บๅ‰ใซ Graph Explorer, Fiddler ใ‚„ Postman ใชใฉใ‚’ไฝฟ็”จใ—ใฆใ€ใ‚ใ‚‰ใ‹ใ˜ใ‚ไฝฟ็”จใ™ใ‚‹ REST ใ‚’็ขบ็ซ‹ใ—ใฆใŠใใ“ใจใ‚’ใŠๅ‹งใ‚ใ—ใพใ™ใ€‚ใƒ‡ใƒใƒƒใ‚ฐๆ–นๆณ•ใซใคใ„ใฆใฏใ€ไปฅไธ‹ใ‚’ใ”ๅ‚่€ƒใซใ—ใฆใใ ใ•ใ„ใ€‚

ใ‚ฟใ‚คใƒˆใƒซ : Microsoft Graph ใ‚’ไฝฟ็”จใ—ใŸ้–‹็™บใซไพฟๅˆฉใชใƒ„ใƒผใƒซ็พค
ใ‚ขใƒ‰ใƒฌใ‚น : https://blogs.msdn.microsoft.com/office_client_development_support_blog/2016/12/13/tools-for-development-with-microsoft-graph/

ไปŠๅ›žใฎๆŠ•็จฟใฏไปฅไธŠใงใ™ใ€‚ย 

ย 

ย 

โ†ง

Azure AD โ€“ How to register your own SAML-based application using new Azure Portal

$
0
0

With new Azure Portal (https://portal.azure.com/), Azure AD provides very flexible SAML-based configuration, but some folks ask me where to do that ?
In this post, I show you the answer for this question using some bit of SAML-based federation sample code of PHP and Node.js.

Note : For the settings usingย Azure Classic Portal (Azure Management Portal), see my previous posts โ€œAzure AD Web SSO with PHP (Japanese)โ€ and โ€œAzure AD Web SSO with Node.js (Japanese)โ€œ.

Settings with Azure Portal

First of all, Iโ€™ll ย show you how the SAML settings page is improved by new Azure Portal.

When you want to register own SAML-based application, select โ€œAzure Active Directoryโ€ in Azure Portal,ย click โ€œEnterprise applicationsโ€ menu, and push โ€œaddโ€ button.
You can select a lot of pre-defined (registered) applications (like Salesforce, Google, etc), but you click โ€œadd your ownโ€ link on top of this page.

In the next screen, select โ€œDeploying an existing applicationโ€ drop-down and input your app name.

http://i1155.photobucket.com/albums/p551/tsmatsuz/20170101_Set_AppName_zpsojgxd9e4.jpg

After youโ€™ve added your application, select โ€œSingle sign-onโ€ menu in your app settings page and select โ€œSAML-based Sign-onโ€ in โ€œModeโ€ drop-down menu. (see the following screenshot)
By these steps, you can configure several SAML settings in this page.

First, you must specify your application identifier (which is used as entityID in SAML negotiation), and your appโ€™s reply url. (Here we set โ€œmytestappโ€ as identifier. We use this identifier in the following custom federation applications.)
You can also specify the relay state in this section.

In the next โ€œattributesโ€ section, you can set the value of user identifier (which is returned as NameID by Azure AD in SAML negotiation), and you can also select the claims which should be returned.
When you were using Azure Classic Portal (https://manage.windowsazure.com/), you cannot specify this value and Azure AD always returned the original pairwise identifier as NameID. Some applications which need the e-mail format user principal name as NameID was used to have the trouble to federate Azure AD, but now we donโ€™t have these kind of troubles with new Azure Portal settings.

In the next โ€œcertificateโ€ section, you can create the certificate and make the rollover certificate active. Here we create this certificate and make active for the following custom code.

Custom code by PHP (simpleSAMLphp)

Now letโ€™s start to create the code and federate with Azure AD.
First we use PHP, and here we use simpleSAMLphp for the SAML federation.

You first install IIS and PHP in your dev machine, and make sure that the following extensions are set in PHP.ini file.

extension=php_openssl.dll
extension=php_ldap.dll

Next you download simpleSAMLphp (see here), and publish {simplesamplephp install location}/www folder using IIS manager.

Remember that the page is redirected to https://{published simpleSAMLphp site}/module.php/saml/sp/saml2-acs.php/default-sp, when the user is successfully logged-in to Azure AD with SAML federation. Then you must set this url as โ€œReply URLโ€ in your app settings in Azure Portal. (see the following screenshot)

Open {simplesamplephp location}configconfig.php and change โ€œbaseurlpathโ€ to your previous published url. Moreover you must change โ€œauth.adminpasswordโ€ to your favorite password. (The default password value is โ€œ123โ€.)

<?php
$config = array (
  . . .

  'baseurlpath'           => 'simplesaml/',
  'certdir'               => 'cert/',
  'loggingdir'            => 'log/',
  'datadir'               => 'data/',
  . . .

  /**
   * This password must be kept secret, and modified from the default value 123.
   * This password will give access to the installation page of simpleSAMLphp with
   * metadata listing and diagnostics pages.
   * You can also put a hash here; run "bin/pwgen.php" to generate one.
   */
  'auth.adminpassword'    => 'test',
  'admin.protectindexpage'  => false,
  'admin.protectmetadata'    => false,
  . . .

Edit {simplesamplephp location}configauthresources.php and make sure to change entityID with the previous application identifier.

$config = array(
  . . .

  'default-sp' => array(
    'saml:SP',

    'entityID' => 'mytestapp',

    'idp' => NULL,

    'discoURL' => NULL
  ),
  . . .

Next you set the federation information using simpleSAMLphp UI, and you must copy the setting information in Azure Portal beforehand.
First you must click โ€œConfigure {your app name}โ€ in your app single sign-on settings page in Azure Portal.

In the configuration page, click โ€œSAML XML Metadataโ€ link (see the following screenshot), and the metadata file is downloaded in your local machine. Please copy the content (text) in the downloaded file.
Note that this string content includes the digital signature by the certificate. For this reason, you shouldnโ€™t never change this text, even if itโ€™s space character.

http://i1155.photobucket.com/albums/p551/tsmatsuz/20170101_Download_Metadata_zpsv7qaawcz.jpg

Next you go to the simpleSAMLphp www site (in this example, https://localhost/simplesaml/index.php) using your web browser.
In the simpleSAMLphp settings page, click โ€œFederationโ€ tab and โ€œLogin as administratorโ€ link. When the login screen is prompted, you enter โ€œadminโ€ as user id and password which you specified above.

http://i1155.photobucket.com/albums/p551/tsmatsuz/20170101_SimpleSaml_Login_zpsx2lvg0sk.jpg

After logged-in, click โ€œXML to simpleSAMLphp metadata converterโ€ link in the page (see the above screenshot), and the following metadata parser page is displayed.
Please paste your metadata which is previously copied into this textbox, and push โ€œParseโ€ button. Then the converted metadata settings (which is written with PHP) is displayed in the bottom of this page. (See the following screenshot.)
Copy this PHP code, and paste into {simplesamplephp location}metadatasaml20-idp-remote.php.

<?php
...

$metadata['https://sts.windows.net/16d103a1-a264-4d36-9b52-51fa01ce5c2e/'] = array (
  'entityid' => 'https://sts.windows.net/16d103a1-a264-4d36-9b52-51fa01ce5c2e/',
  'contacts' => 
  array (
  ),
  'metadata-set' => 'saml20-idp-remote',
  'SingleSignOnService' => 
  array (
    0 => 
    array (
      'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
      'Location' => 'https://login.windows.net/16d103a1-a264-4d36-9b52-51fa01ce5c2e/saml2',
    ),
    1 => 
    array (
      'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
      'Location' => 'https://login.windows.net/16d103a1-a264-4d36-9b52-51fa01ce5c2e/saml2',
    ),
  ),
  'SingleLogoutService' => 
  array (
    0 => 
    array (
      'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
      'Location' => 'https://login.windows.net/16d103a1-a264-4d36-9b52-51fa01ce5c2e/saml2',
    ),
  ),
  'ArtifactResolutionService' => 
  array (
  ),
  'keys' => 
  array (
    0 => 
    array (
      'encryption' => false,
      'signing' => true,
      'type' => 'X509Certificate',
      'X509Certificate' => 'MIIC8DC...',
    ),
  ),
);

Note : On the contrary, if you want to set SAML federation SP (service provider) metadata (which includes the value of SingleLogoutService, etc) into Azure AD, you can get this XML from simpleSAMLphp and set it into Azure AD using the application manifest in Azure AD settings.

The settings of simpleSAMLphp has all done !

Letโ€™s create your own PHP (.php) code with simpleSAMLphp like the following code. This sample code is just showing all claims returned by Azure AD.

<?php
  require_once("../simplesamlphp-1.11.0/lib/_autoload.php");
  $as = new SimpleSAML_Auth_Simple('default-sp');
  $as->requireAuth();
  $attributes = $as->getAttributes();
?>
<div style="font-weight: bold;">Hello, PHP World</div>
<table border="1">
<?php  foreach ($attributes as $key => $value): ?>
  <tr>
    <td><?=$key;?></td>
    <td><?=$value[0];?></td>
  </tr>
<?php endforeach;?>
</table>

Letโ€™s see how it works.
If you access to this PHP page with your web browser, the page is redirected to the idp selector. In this page, please select the metadata of Azure AD, and push โ€œSelectโ€ button.

Then the page is redirected into the Azure AD login (sign-in) page. Please input your login id and password.

When the login is succeeded, the returned claims are shown as follows in your custom PHP page.

Custom code by Node.js (express, passport)

When you use Node.js, the concept is the same as before. You can just use your favorite SAML library with your custom code, and configure the library with the registered Azure AD app settings.
Here we use the famous passport module with express framework in Node.js.

First you start to install express framework and express command.

npm install express -g
npm install -g express-generator

Create the project directory, and provision express project by the โ€œexpressโ€ command with the following commands. (The files and folders of template project are deployed, and all related packages are installed.)
After that, you can start and view the express project with your web browser. (Please run by โ€œnpm startโ€œ, and access with your web browser.)

mkdir sample01
express -e sample01
cd sample01
npm install

Install passport and related modules with the following commands.

npm install express-session
npm install passport
npm install passport-saml

Open and edit app.js (the start-up js file for this express framework), and please add the following code (of bold font).
I explain about this code later.

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
var session = require('express-session');
var fs = require('fs');

var SamlStrategy = require('passport-saml').Strategy;
passport.serializeUser(function (user, done) {
  done(null, user);
});
passport.deserializeUser(function (user, done) {
  done(null, user);
});
passport.use(new SamlStrategy(
  {
    path: '/login/callback',
    entryPoint: 'https://login.windows.net/16d103a1-a264-4d36-9b52-51fa01ce5c2e/saml2',
    issuer: 'mytestapp',
    cert: fs.readFileSync('MyTestApp.cer', 'utf-8'),
    signatureAlgorithm: 'sha256'
  },
  function(profile, done) {
    return done(null,
    {
      id: profile['nameID'],
      email: profile['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'],
      displayName: profile['http://schemas.microsoft.com/identity/claims/displayname'],
      firstName: profile['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'],
      lastName: profile['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname']
    });
  })
);

var index = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session(
  {
    resave: true,
    saveUninitialized: true,
    secret: 'this shit hits'
  }));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

app.get('/login',
  passport.authenticate('saml', {
    successRedirect: '/',
    failureRedirect: '/login' })
  );
app.post('/login/callback',
  passport.authenticate('saml', {
    failureRedirect: '/',
    failureFlash: true }),
  function(req, res) {
    res.redirect('/');
  }
);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

I explain about this sample code :

  • When SAML authentication and idp redirection is needed, the entryPoint url (here, https://login.windows.net/16d103a1-a264-4d36-9b52-51fa01ce5c2e/saml2) is used. Please copy this value from your app configuration page in Azure AD, and paste. (see the following screenshot)
  • Please see the routing code, app.get('/login', ...);
    When the user goes to /login by the web browser, the SAML flow is proceeded and the user is redirected to the entryPoint url.
  • The path /login/callback is the reply url. When the authentication is succeeded in the identity provider (Azure AD), the results (SAML response) is returned to this url and the claims (here nameID, emailaddress, displayname, givenname, and surname) are parsed. (see return done(null, { id: ..., email: ..., displayName:..., ... }); in the above code.)
    After that, the page is redirected to /. (Please see the routing code, app.post('/login/callback', ...);)
    Thus please set this url as reply url in Azure AD app settings beforehand.
  • Please copy the X509 cert in Azure AD app settings or download the cert (see the following screenshot), and you set this cert as the passport-saml strategy.
    If you set this cert, the passport-saml module validates the incoming SAML response. (The passport-saml checks if the response is not altered by the malicious code.)

Finally letโ€™s get the returned claims and show these values in your page.
Here, we edit routes/index.js, and modify as follows. Weโ€™re retrieving the userโ€™s displayName and email address, and passing to the view page.

var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
  if(req.isAuthenticated())
    res.render('index', { username: req.user.displayName, mail: req.user.email });
  else
    res.render('index', { username: null});
});

module.exports = router;

Edit views/index.ejs (which is the view page of the previous index.js), and modify as follows.

<!DOCTYPE html>
<html>
  <head>
    <title>SAML Test</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <% if (!username) { %>
    <h2>Not logged in...</h2>
    <% } else { %>
    <h2>Hello, <%= username %>.</h2>
    (your e-mail is <%=mail %>)
    <% } %>
  </body>
</html>

Your programming has finished !

Note : Your app must be hosted by https, and please configure to use https. (Here I donโ€™t describe this steps.)

Please start your app using the following command.

npm start

When you access to /login using your web browser, the page is redirected and the Azure AD sign-in page is displayed.

When you succeed your login, your display name and email are displayed in the top page (index.ejs) as follows.

ย 

If youโ€™re ISV folks, you can submit your own custom app (which is federated with Azure AD) to Azure AD gallery. Everyone can start and use your app (ISV app) federated with Azure AD with a few clicks !

โ†ง
โ†ง

The evolution of the text size limits related to the standard static control

$
0
0


Michael Quinlan wondered about

the text size limits related to the standard static control
.ยน



We start with the resource format, since that was the limiting
factor in the original problem.
The

original 16-bit resource format

represented strings as null-terminated sequences of bytes,
so in theory they could have been arbitrarily large.
However,

16-bit string resources
were limited to 255 characters
because they used a byte count for string length.
My guess is that the resource compiled took this as a cue that
nobody would need strings longer than 255 characters,
so it avoided the complexity of having to deal with a dynamic
string buffer,
and when it needed to parse a string in the resource file,
it did so into a fixed-size 256-byte buffer.



I happen to still have a copy of the original 16-bit resource compiler,
so I can actually verify my theory.
Hereโ€™s what I found:



There was a โ€œread next tokenโ€ function that placed the result
into a global variable.
Parsing was done by asking to read the next token
(making it the current token), and then
and then studying the current token.
If the token was a string,
the characters of the string
went into a buffer of size MAXSTR + 1.
And since string resources have a maximum length of 255,
MAXSTR was 255.



Although the limit of 255 characters did not apply to dialog
controls,
the common string parser stopped at 255 characters.
In theory, the common string parser could have used dynamic
memory allocation to accommodate the actual string length,
but remember that weโ€™re 16-bit code here.
Machines had 256KB of memory,
and no memory block could exceed 64KB.
Code in this era did relatively little dynamic memory allocation;
static memory allocation was the norm.
Itโ€™s like everybody was working on an embedded system.



Anyway, thatโ€™s where the 255-character limit for strings
in resource files comes from.
But thatโ€™s not a limit of the resource file format or of static
text controls.
Itโ€™s just a limit of the resource compiler.
You can write your own resource compiler that
generates long strings if you like.



Okay, so what about the static text control?
The original 16-bit static text control had a text size
limit of 64KB
because 16-bit.
This limit carried forward to Windows 95 because the
static text control in Windows 95 was basically a 16-bit
control with some 32-bit smarts.



On the other hand, Windows NTโ€™s standard controls were
32-bit all the way through (and also Unicode).
The limits consequently went up from 64KB to 4GB.
Some messages needed to be revised in order to be able
to express strings longer than 64KB,
For example,
the old EM_GETยญSEL message returned
the start and end positions of the selection as two
16-bit integers packed into a single 32-bit value.
This wouldnโ€™t work for strings longer than 65535 characters,
so the message was redesigned so that the wParam
and lParam are pointers to 32-bit integers
that receive the start and end of the selection.



Anyway, now that the 16-bit world is far behind us,
we donโ€™t need to worry about the 64KB limit for static
and edit controls.
The controls can now take all the text you give it.ยฒ



ยน And then for some reason
Erkin Alp Gรผney said that Iโ€™m
โ€œemployed
as a PR guy
.โ€
I found this statement very strange,
because not only am I not employed as a PR guy,
I have basically no contact with PR at all.
The only contact I do have is that
occasionally they will send me a message
saying that they are upset at something I wrote.
I remember that they were very upset about my story
that shared

some trivia about the //build 2011 conference

because it (horrors) talked about some things
that went wrong.
(And as Tom West

noted
,
it wouldnโ€™t seem to be a good idea for PR to employ someone

with the social skills of a thermonuclear device
.)



ยฒ Well, technically no.
If you give a string longer than 4GB, then it wonโ€™t be able
to handle that.
So more accurately, it can handle all the text you would
give it, provided youโ€™re not doing something ridiculous.
I mean, you really wouldnโ€™t want to manipulate 4GB of data
in the form of one giant string.
And no human being would be able to read it all anyway.

โ†ง

Forum Moderation Best Practice โ€“ Propose an answer and then mark it 7 days later

$
0
0

Forum Ninjas Blog

Hello! This postย continues the conversation from last weekโ€™s blog post:

.

I ended it by pointing to one article in particular, where we (Microsoft TechNet/MSDN forum owners) hammered out some hard guidelines:

.

So what are those guidelines? I thought youโ€™d never ask!

Today weโ€™ll dig into the first two:

  1. Propose an answer first. Give the Asker/OP a chance to select the right answer.
  2. After proposing an answer, wait one week (7 days), and then mark the answer(s). This gives the OP more than enough time to return. More often than not, the OP will not mark an answer and will not reply again. After waiting the week, then mark the answer. The Asker/OP is your client, and you want to help him and make him happy.ย Many OPs have gotten angry when Moderators mark answers without waiting a few days (waiting 7 days sets a clear message that the Asker/OP is the client and that you are patient). Plus the people who answer the questions get 5 more points (15 Recognition Points instead of 10) if the Asker/OP is the one who marks the reply as an answer. One exception (toย proposing first)ย is if the thread hasnโ€™t been responded to for over 6 months (youโ€™re cleaning up a forum). But even then, itโ€™s better to propose first if youโ€™re uncertain about an answer.

Well, it kind of answers itself as to โ€œwhyโ€ we ask this. First, we want the OP to mark it, but if the OP isnโ€™t going to return (which too often is the case), then we still want to mark it. Second, this makes people feel valued, which they are. They donโ€™t answer questions to get stats, points, or medals, but it just simply feels good to be appreciated, and we greatly appreciate the community contributions!

And the bottom line is that the more questions are marked as answered, the more people answer questions. If we donโ€™t mark answers, most often, the forum dries up. A lot of people still ask questions, but fewer and fewer people answer them. Thatโ€™s not the kind of community we want.

Remember, the Asker/OP is the client. So if they unmark or unpropose, then thatโ€™s okay. We just want to make sure theyโ€™re willing to come back on, explain why, and help us move the topic forward.

Ideally, we built a moderation team for that particular forum, so we might have different moderators/answerers propose and mark answers.

Of course, this will lead to the debate of whether someone should propose their own answers. This is a meaty enough topic for another day. While we do allow that capability for a reason (it is by design that you can do this), it should be used as a last resort. Ideally, the moderation teams work together, so that itโ€™s not necessary. So thatโ€™s the short explanation. But weโ€™ll dig into it some more later.

If you feel overwhelmed, like you donโ€™t have a moderator team (youโ€™re the team) for your forum, then please reply to this post with a nominee in your forum to help you out! We make people Answerers if they have at least 6 months of experience in that forum (so the forum community knows them), they have 100 answered questions, and they have 1K Recognition Points. Thatโ€™s the bar that can be equally measured. To be made a Moderator, weโ€™d like to see you faithful in the Answerer role for 3+ months, or an MVP or Microsoft employee. And for both roles, you have to agree to follow the Forum Moderation Guidelines (in the article linked below).

Read all the related guidelines on TechNet Wiki here:

.

May the Forums Be With You! (Donโ€™t be a rogue one.)

โ€“ Ninja Ed

โ†ง

Performing Application Upgrades on Azure VM Scale Sets

$
0
0

Virtual Machine Scale Sets (VMSS) are an awesome solution available on Azure, providing autoscale capabilities and elasticity for your application. I was recently working with a customer who was interested in leveraging VMSS on their web tier and one of the points we focused on was how to do an upgrade of an application running on a VMSS and what the capabilities were in this regard. In this post, weโ€™ll walk through one method of upgradingย an ASP.NET application that is running on a VMSS.

For the creation and upgrade of the scale set, weโ€™ll utilize an Azure Resource Manager (ARM) template from the Azure Quickstart GitHub repository. If youโ€™re not familiar with the Quickstart repo, itโ€™s a large and ever-growing repo of ARM templates that can be used to deploy almost every service on Azure. Check it out further when you have some time! The ARM template for this exercise can be found atย https://github.com/Azure/azure-quickstart-templates/tree/master/201-vmss-windows-webapp-dsc-autoscale.

Create VMSS via portal and PowerShell

To start, letโ€™s create the VMSS. The application weโ€™ll be deploying will be a very simple ASP.NET web application, essentially the default app when you create a new ASP.NET project with a minor text modification to display a version number so we can validate the upgrade itself. Super simple, but can easily be extended to more complex and complete applications. There are two ways to kick off the VMSS ARM template deployment; through the Azure portal and through PowerShell. Weโ€™ll go through both methods.

Deployment via Azure Portal

Kicking off the deployment through the Azure Portal is easy, as you can use the โ€œDeploy To Azureโ€ linkย in the Quickstart repo.
deploy-to-azure-button
Click the link and that will open the portal and land you in the template deployment dialog for this template, should look something like this:

portal-deploy-1

From there, youโ€™ll want to fill out the various fields. Most of them are self explanatory, but Iโ€™ll call out a couple of items. The _artifacts Location parameter is the base location for the artifacts weโ€™ll be using (ASP.NET WebDeploy package and DSC scripts) which points us to the raw storage in the Quickstart repo. In this case we can leave the _artifacts Location Sas Token blank as this is only needed if you need to provide a SAS token, and all of the artifacts here are publicly available, no token needed. We will then specify the rest of the path to each artifact in the Powershelldsc Zip and Web Deploy Package parameters. The Powershelldsc Update Tag Version parameter will be used in the upgrade, so hold tight and Iโ€™ll go through that shortly. For this deployment youโ€™ll want to enter or select a resource group, provide a name for the VMSS and enter a password. The rest of the values can be left at their defaults unless you want to change them.

Click purchase when youโ€™re ready to go and wait for the deployment to complete, which may take 30 minutes or so. Once complete you can validate that everything is working by pulling up the web page the VMSS is hosting. To get this, pull up your VMSS in the portal and youโ€™ll see the public IP address. The web page can be found at http://x.x.x.x/MyApp replacing x.x.x.x with your public IP. Pull up that page and you should see the home page indicating youโ€™re running version 1.0.

web-site-1

Deployment via PowerShell

For deployment via PowerShell, youโ€™ll need two files locally for the deployment. Youโ€™ll need the ARM template and the parameter file. Save these to a local directory, in this case weโ€™ll use C:VMSSDeployment.

Open the parameter file and weโ€™ll want to make a few updates. Update the vmssName parameter to be the name you want for your VMSS (3-61 characters and globally unique across Azure). Next, update the adminPassword parameter with the password of your choice. Finally, update the _artifactsLocationSasToken parameter to "", empty quotes (the null value is part of the Quickstart repo requirements). Save and exit this file.

Now weโ€™re ready to kick off deployment. Iโ€™ve simplified this and am leaving out some error checking and pre-flight validation. If you want more details on how to ensure you properly handle errors there is a great blog post from Scott Seyman that walks you through all these details. In our case, weโ€™ll create a new resource group and then kick off the ARM template deployment into that resource group. Open a PowerShell session, log in to your Azure account and run the following commands.

$resourceGroupName = "VMSSDeployment"
$location = "West Central US"
New-AzureRmResourceGroup -Name $resourceGroupName -Location $location

$templateFilePath = "C:VMSSDeploymentazuredeploy.json"
$parametersFilePath = "C:VMSSDeploymentazuredeploy.parameters.json"
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $templateFilePath -TemplateParameterFile $parametersFilePath -Verbose

Once the template has deployed successfully youโ€™ll get a response back with the details on the deployment.

DeploymentName          : azuredeploy
ResourceGroupName       : VMSSDeployment
ProvisioningState       : Succeeded
Timestamp               : 12/29/2016 7:08:43 PM
Mode                    : Incremental
TemplateLink            : 
Parameters              : 
                          Name             Type                       Value     
                          ===============  =========================  ==========
                          vmSku            String                     Standard_A1
                          windowsOSVersion  String                     2016-Datacenter
                          vmssName         String                     vmssjb2   
                          instanceCount    Int                        3         
                          adminUsername    String                     vmssadmin 
                          adminPassword    SecureString                         
                          _artifactsLocation  String                     https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-vmss-windows-webapp-dsc-autoscale
                          _artifactsLocationSasToken  SecureString                         
                          powershelldscZip  String                     /DSC/IISInstall.ps1.zip
                          webDeployPackage  String                     /WebDeploy/DefaultASPWebApp.v1.0.zip
                          powershelldscUpdateTagVersion  String                     1.0       
                          
Outputs                 : 
DeploymentDebugLogLevel :

To validate the web site letโ€™s get the public IP address.

Get-AzureRmPbulicIpAddress -ResourceGroupName VMSSDeployment

Now you can plug in your IP address (http://x.x.x.x/MyApp) and confirm that the page comes up successfully.

Upgrade the application

So now weโ€™ve got a web site running version 1.0, but we want to upgrade it to the newly released version 2.0. Lets go through the process to make this happen in both the Azure Portal and through PowerShell.

Upgrade via Azure Portal

To kick off the deployment in the Azure Portal weโ€™ll want to redeploy the template. In the portal, navigate to your resource group, select Deployments and click the Redeploy button. This will pop open the familiar custom template deployment dialog with some information pre-populated, weโ€™ll make a few updates here to do the upgrade.

Update the Resource group parameter to use the existing resource group your VMSS currently resides in. Validate that the Vmss Name parameter is the same as you specified on the original deployment. These are both important so that the deployment is to the existing VMSS and not to a new VMSS in a new resource group. In the Admin Password parameter enter the same password you originally entered. Now, to update the application weโ€™ll change two additional parameters. Update the Web Deploy Package to reference /WebDeploy/DefaultASPWebApp.v2.0.zip, and update the Powershelldsc Update Tag Version to 2.0.
portal-upgrade-1

Once thatโ€™s all set, click Purchase to deploy the updated template. Since all of our resources already exist (storage accounts, load balancer, VMSS, etc.) the only updates will be to the VMs in the scale set. Once the deployment is complete, pull up your web page and you should see the newly deployed version 2.0.

web-site-2

Upgrade via PowerShell

The process to upgrade through PowerShell is equally easy. Pop open the parameters file you used on your original deployment. Update the webDeployPackage parameter to reference /WebDeploy/DefaultASPWebApp.v2.0.zip and set the powershelldscUpdateTagVersion to 2.0. Save and exit the file.
Next, re-run the command to deploy the template.

New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $templateFilePath -TemplateParameterFile $parametersFilePath -Verbose

Once finished, pull up your web site and validate that itโ€™s now running version 2.0.

Under the hood

So how does this all work? Letโ€™s go through several key pieces to this solution.

WebDeploy

Weโ€™re using a WebDeploy package to deploy the ASP.NET application on the servers. This give us a nice, self contained application package that makes it easy to deploy to one or more web servers. I wonโ€™t go into too much detail on this other than I essentially followed the steps referenced in this document. I saved this file locally and uploaded it to the repo to make it available in the deployment. In this case there are two versions with a slightly different configuration to illustrate the upgrade process as described, version 1.0 and version 2.0.

PowerShell DSC script

The servers themselves are configured with a PowerShell DSC script. This script installs IIS and all the necessary dependencies, installs WebDeploy and deploys the WebDeploy package that gets passed as a script parameter from the ARM template itself.

You can use the Publish-AzureRmVmDscConfiguration cmdlet to create the zip file needed for the deployment. This can either create the file locally or upload it to Azure storage for you so itโ€™s available in an Internet accessible location. In this case I created the file locally and uploaded it to the Quickstart repo.

PowerShell DSC extension

The PowerShell DSC VM extension is used to run the aforementioned DSC script on each of the VMs as they are provisioned. We take the path for the WebDeploy package and pass that through as a parameter to the script so it knows where to get it from. The upgrade process is triggered when the forceUpdateTag parameter is updated. The DSC extension sees the different value and will re-run the extension on all the VMs. When we update the path to the WebDeploy package as part of the upgrade process, this pulls down the 2.0 version of the web site and deploys it.

"extensionProfile": {
            "extensions": [
              {
                "name": "Microsoft.Powershell.DSC",
                "properties": {
                  "publisher": "Microsoft.Powershell",
                  "type": "DSC",
                  "typeHandlerVersion": "2.9",
                  "autoUpgradeMinorVersion": true,
                  "forceUpdateTag": "[parameters('powershelldscUpdateTagVersion')]",
                  "settings": {
                    "configuration": {
                      "url": "[variables('powershelldscZipFullPath')]",
                      "script": "IISInstall.ps1",
                      "function": "InstallIIS"
                    },
                    "configurationArguments": {
                      "nodeName": "localhost",
                      "WebDeployPackagePath": "[variables('webDeployPackageFullPath')]"
                    }
                  }
                }
              }
            ]
          }

VMSS upgrade process

There are two modes of upgrades for VMSS, Automatic and Manual. Automatic will perform the upgrade across all VMs at the same time and may incur downtime. Manual gives the administrator the ability to roll out the upgrade one VM at a time, allowing you to minimize any possible downtime. In this case weโ€™re using Automatic since weโ€™re not actually redeploying the VMs, weโ€™re just re-running the DSC script on each one to deploy a new application. You can read more about these options and how to perform a manual upgrade here. Do note that you may see the VMs scale depending on what you specify in the template and what the current running state is. These will scale back up or down based on your metrics once the deployment is complete.

"upgradePolicy": {
          "mode": "Automatic"
}

Wrap up

Thatโ€™s about it. I hope this provided you with a good example of how to perform an upgrade of an application across a VMSS. Be sure to read through the referenced documentation and browse through the Quickstart repo for other ARM templates that can be used across Azure.

โ†ง

booting Windows from a VHD

$
0
0

The easiest way to have multiple Windows versions available on the same machine is to place some of them into VHDs, and then you can boot an OS directly from a VHD. The boot loader stays shared between all of them on the original C: drive which might have or not have its own Windows too), just each VHD gets its own entry created in the Boot Configuration Database, and the OS can be selected through a menu at boot time. The drive letters will usually shift when you boot from a VHD: the VHD with the OS would be assigned the letter C:, and the otherย  drives will move, although itโ€™s possible to tell an image to use a different drive letter.

Before we go into the mechanics of it, an important note: the image in the VHD must be generalized. When Windows boots for the first time, it configures certain things, like the machine name, various initial values for generation of the random GUIDs, some hardware configuration information, which are commonly known as the specialization. Duplicating the specialized images is a bad idea, and might not work altogether. The right way to do it is by either generating a fresh VHD that had never been booted yet or by taking a booted image and generalizing it with the Sysprep tool.

An of easy way to add a VHD to the boot menu is to mount it on some drive, say E:, and run:

bcdboot e:windows /d /addlast

Bcdboot will create an entry for it. Along the way it will make sure that the boot loader on the disk is at least as new as the image on the VHD, updating the boot loader from VHD if necessary. An older boot loader might now be able to load the newer version of Windows, so this update is a good thing. The option /d says to keep the default boot OS rather changing it to the new VHD, and /addlast tells to add the new OS to the end of the list rather than to the front.

A caveat is that for bcdboot to work, the VHD must be mounted on a drive letter, not on a directory. If you try to do something like

bcdboot.exe e:vhdimg1mountdirWindows /d

then bcdboot will create an incorrect path in the BCD entry that includes all the current mount path, and the VHD wonโ€™t boot.

By the way, if you use Bitlocker on your machine, make sure to temporarily disable it before messing with the BCD modifications, or youโ€™ll have to enter the full long decryption key on the next reboot by the PowerShell command:

Suspend-BitLocker -RebootCount 1

This command temporarily disables the BitLocker until the next reboot, when it gets auto-enabled back. The reason for this is that normally this key gets stored in a TPM which requires the boot sequence signature to match the remembered one to divulge this information. Changing the boot loader code or data changes this signature. And no, apparently there is no way to generate this signature other than by actually booting the machine and remembering the result. So the magic suspension command copies the key to a place on disk, and on the next reboot puts the key back into TPM along with the new boot signature, removing the key from the disk.

Now about what goes on inside, and what else can be done. BCD contains a number of sections of various types. Two entry types are particularly important for this discussion: the Boot Manager and the Boot Loader. You can see them by running

bcdedit /enum

There is one Boot Manager section. Boot manager is essentially the first part of the boot loader, and the selection of the image to boot happens there. And there is one Boot Loader section per each configured OS image, describing how to load that image.

The more interesting entries in the Boot Manager section are:

defaultย is the GUID of the Boot Loader section that will be booted by default. On a booted system the value of default is usually shown as {current}. This is basically because bcdedit defines two symbolic GUIDs for convenience: {current} is the GUID of the Boot Loader section of the currently booted OS, {default} is the GUID of the Boot Loader section that is selected as default in the Boot Manager section. There also are some other pre-defined GUIDs used for specific section types, like {bootmgr} used for the Boot manager section.

By the way, be careful with the curly braces when calling bcdedit from PowerShell: PowerShell has its own syntactic meaning for them, so make sure to always put the strings that contain the curly braces into quotes.

displayorderย is the list of Boot Loader section GUIDs for the boot menu.

timeoutย is the timeout in seconds before the default OS is booted automatically.

The Boot Loader section has quite a few interesting settings:

device and osdevice tell theย disk that contain the OS. They would be usually set to the same values, although technically I think device is the diskย that contains theย Winloader (the last stage of the boot loader than then loads the kernel) while osdevice is the disk that contains the OS itself. Their values are formatted as โ€œsubtype=valueโ€, like โ€œpartition=C:โ€ to load the OS directly from a partitionย or โ€œvhd=[locate]vhdsimg1.vhdโ€ to boot from a VHD.ย  The partition names in this VHD string have multiple possible formats. โ€œ[locate]โ€ means that the boot loader will automatically go through all the drives it finds and try to find a file at this path. A string like โ€œ[e:]โ€ will mean the specific drive E: at the time when you run bcdedit. This is an important distinction, since when booting from the different VHDs the drive mappings may be different (and very probably will be different at least between the VHDs and the OS on the main partition). In this format bcdedit finds and stores in its database the resolved partition ID, not the letter as such, so it can find the partition later no matter what letter it gets. If you run โ€œbcdedit /enumโ€ later when booted from a different VHD, the letter shown will match the mapping in that OS. And finally the string like โ€œe:โ€ will mean the partition that is seen as E: by the boot manager, and this might be difficult to predict right, so itโ€™s probably better not used. For all I can tell, in the โ€œpartition=โ€ specification the letter is always treated similar to the โ€œ[e:]โ€ format for VHD, i.e. the stored value is the resolved identity of the partition.

path is the path of Winloader (the last stage of the boot loader that loads the kernel) on the device. It comes in two varieties: winload.exe for the classically-partitioned disks with MBR and winload.efi for the machines with the UEFI BIOS that use the new GPT format of the partition table. If you use the wrong one, it wonโ€™t boot, so the best bet is to copy the type from another Boot Loader entry that is known to be right. The path to it might also come in two varieties: either โ€œWINDOWSsystem32โ€ or โ€œWindowsSystem32Bootโ€. The first path is a legacy one that would still work on the Windows client or full server. The second one is the new one that would work on all the Windows versions, including the tiny ones like NanoServer, IOT or Phone.

description is the name shown in the boot menu.

systemroot is the location of the OS on the osdevice, usually just โ€œWINDOWSโ€.

hypervisorlaunchtype enables the Hyper-V, โ€œAutoโ€ isย a good value for it.

bootmenupolicy selects how the menu for the OS selection is displayed. Theย value placed there by the usual Windows installย is โ€œstandardโ€ which does the selection in the graphical mode and is quite slow painful: basically, the graphical-mode selection is done in Winloader, so if you select a different OS, it has to go through the getting a different Windloader that matches that OS, which is done by remembering the selection somewhere on disk and then rebooting the machine, so that next time the right Winloader is picked. The much better value is โ€œlegacyโ€ which does the selection in the basic text mode directly in the Boot Manager, so the boot happens fast.

bootstatuspolicy can be set to โ€œDisplayBootFailuresโ€ for the better diagnostics.

bootlog and sos enable some kinds of extra diagnostics when set to โ€œyesโ€. Iโ€™m not sure where exactly does this diagnostics go.

detecthal forces the re-enumeration of the available hardware on boot when set to โ€œyesโ€. It doesnโ€™t matter for the generalized images that would do this anyway. But it might help when moving a VHD with an OS from one physical machine to another.

By the way, bcdedit has two ways of specifying the settings, one for the current section, another one for a specific section. For the current section it looks simply like:

bdcedit /detecthal yes

For a specific section (identified by a GUID or one of the symbolic pseudo-GUIDs) this becomes:

bcdedit /set {SectionGuid} detecthal yes

You can also select the BCD store that bcdedit acts on. For an MBR machine the store is normally located in C:BootBCD.ย  For an EFI machine the BCD store is located in a separate EFI System partition, under EFIMicrosoftBootBCD. If youโ€™re really interested in looking at theย System partition, you can mount it with Disk Manager or with PowerShell. There is a bit of a caveat with mounting the System partitions: it canโ€™t be mounted to a path, only to a drive letter, and if you unmount it, that drive letter becomes lost until the next reboot. If you want to say look at theย system partitionsย on a lot ofย  VHDs, a better strategy is to change the partition type from System to Basic, mount it, do your thing, then unmount it and change the type back to System. This way you wonโ€™t leak the drive letters.

Returning to the subject, ย Iโ€™ve made a script that helps create theย BCD entries for the VHDs at will. It uses my sed for PowerShell for parsing the output of bcdedit. The main function is Add-BcdVhd and is used like this:

Add-BcdVhd -Path C:vhdimg1.vhd -Description "Image 1" -Reset

Here is the implementation:

$bindir = Split-Path -parent $PSCommandPath 
Import-Module -Force -Scope Global "$bindirTextProc.psm1"

$ErrorActionPreference = "Stop"

function Get-BootLoaderGuid
{
<#
.SYNOPSIS
Extracts the GUID of a Boot Loader entry from the output of
bcdedit /v or /enum. The entry is identified by its description or by its
device, or otherwise just the first entry.
#>
ย ย ย  param(
ย ย ย ย ย ย ย  ## The output from bcdedit /v.
ย ย ย ย ย ย ย  [string[]] $Text,
ย ย ย ย ย ย ย  ## Regexp pattern of the description used in the boot menu, to identify the section.
ย ย ย ย ย ย ย  [string] $DescMatch,
ย ย ย ย ย ย ย  ## Regexp pattern of the device used in this the section.
ย ย ย ย ย ย ย  [string] $DevMatch
ย ย ย  )

ย ย ย  $script:cur_desc = $DescMatch
ย ย ย  $script:cur_dev = $DevMatch
ย ย ย  
ย ย ย  $Text | xsed -Select "START",{
ย ย ย ย ย ย ย  if ($_ -match "^Windows Boot Loader") {
ย ย ย ย ย ย ย ย ย ย ย  $script:found_desc = !$cur_desc
ย ย ย ย ย ย ย ย ย ย ย  $script:found_dev = !$cur_dev
ย ย ย ย ย ย ย ย ย ย ย  $script:ident = $null
ย ย ย ย ย ย ย ย ย ย ย  skip-textselect
ย ย ย ย ย ย ย  }
ย ย ย  },{
ย ย ย ย ย ย ย  if ($_ -match "^identifier ") {
ย ย ย ย ย ย ย ย ย ย ย  $script:ident = $_
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย  if ($cur_desc -and $_ -match "^description ") {
ย ย ย ย ย ย ย ย ย ย ย  $d = $_ -replace "^description *", ""
ย ย ย ย ย ย ย ย ย ย ย  if ($d -match $cur_desc) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  $script:found_desc = $true
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย  if ($cur_dev -and $_ -match "^device ") {
ย ย ย ย ย ย ย ย ย ย ย  $d = $_ -replace "^device *", ""
ย ย ย ย ย ย ย ย ย ย ย  if ($d -match $cur_dev) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  $script:found_dev = $true
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย  if ($ident -and $found_desc -and $found_dev) {
ย ย ย ย ย ย ย ย ย ย ย  Set-OneLine $ident
ย ย ย ย ย ย ย ย ย ย ย  Skip-TextSelect "END"
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย  if ($_ -match "^$") {
ย ย ย ย ย ย ย ย ย ย ย  Skip-TextSelect "START"
ย ย ย ย ย ย ย  }
ย ย ย  },"END" | % { $_ -replace "^.*({[^ ]+}).*", '$1' }
}
Export-ModuleMember -Function Get-BootLoaderGuid

function Add-BcdVhd
{
ย ย ย  <#
ย ย ย  .SYNOPSIS
ย ย ย  Add a new VHD image to the list of the bootable images.
ย ย ย  #>

ย ย ย  param(
ย ย ย ย ย ย ย  ## Path to the VHD image (can be any, will be automatically converted
ย ย ย ย ย ย ย  ## to the absolute path without a drive.
ย ย ย ย ย ย ย  [Parameter(
ย ย ย ย ย ย ย ย ย ย ย  Mandatory = $true
ย ย ย ย ย ย ย  )]
ย ย ย ย ย ย ย  [string] $Path,
ย ย ย ย ย ย ย  ## The user-readable description that will be used in the boot menu.
ย ย ย ย ย ย ย  [Parameter(
ย ย ย ย ย ย ย ย ย ย ย  Mandatory = $true
ย ย ย ย ย ย ย  )]
ย ย ย ย ย ย ย  [string] $Description,
ย ย ย ย ย ย ย  ## Enable the debugging mode
ย ย ย ย ย ย ย  [switch] $BcdDebug,
ย ย ย ย ย ย ย  ## Enable the eventing mode
ย ย ย ย ย ย ย  [switch] $BcdEvent,
ย ย ย ย ย ย ย  ## For a fresh VHD that was never booted, there is no need to
ย ย ย ย ย ย ย  ## force the fioorce the detection of HAL.
ย ย ย ย ย ย ย  [switch] $Fresh,
ย ย ย ย ย ย ย  ## Enable the boot diagnostic settings.
ย ย ย ย ย ย ย  [switch] $Diagnose,
ย ย ย ย ย ย ย  ## If the entry exists, delete it and create from scratch.
ย ย ย ย ย ย ย  [switch] $Reset
ย ย ย  )

ย ย ย  # Convert the path to absolute and drop the drive letter
ย ย ย  $Path = Split-Path -NoQualifier ((Get-Item $Path).FullName)

ย ย ย  # Escape the regexp characters
ย ย ย  $pathMatch = $Path -replace "([[]\.()*+])", '$1'
ย ย ย  $pathMatch = "^vhd=.*]$pathMatch`$"

ย ย ย  $descMatch = $Description -replace "([[]\.()*+])", '$1'
ย ย ย  $descMatch = "^$descMatch`$"

ย ย ย  $bcd = @(bcdedit /enum)
ย ย ย  if (!$?) { throw "Bcdedit error: $bcd" }

ย ย ย  # Check if this section is already defined
ย ย ย  $guid_by_descr = Get-BootLoaderGuid -Text $bcd -DescMatch $descMatch
ย ย ย  $guid_by_path = Get-BootLoaderGuid -Text $bcd -DevMatch $pathMatch

ย ย ย  #Write-Host "DEBUG Path match: $pathMatch"
ย ย ย  #Write-Host "DEBUG Descr match: $descMatch"
ย ย ย  #Write-Host "$guid_by_descr by descriprion, $guid_by_path by path"

ย ย ย  if ($guid_by_descr -ne $guid_by_path) {
ย ย ย ย ย ย ย  throw "Found conflicting definitions of existing sections: $guid_by_descr by descriprion, $guid_by_path by path"
ย ย ย  }

ย ย ย  $guid = $guid_by_descr

ย ย ย  if ($guid -and $Reset) {
ย ย ย ย ย ย ย  bcdedit /delete "$guid"
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย ย ย ย ย  $guid = $null
ย ย ย  }

ย ย ย  if (!$guid) {
ย ย ย ย ย ย ย  Write-Host "Copying the current entry"
ย ย ย ย ย ย ย  $bcd = $(bcdedit /copy "{current}" /d $Description)
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error: $bcd" }
ย ย ย ย ย ย ย  $guid = $bcd -replace "^The entry was successfully copied to {(.*)}.*", '{$1}'
ย ย ย ย ย ย ย  if ($guid) {
ย ย ย ย ย ย ย ย ย ย ย  Write-Host "The new entry has GUID $guid"
ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย  throw "Bcdedit error: $bcd"
ย ย ย ย ย ย ย  }
ย ย ย  }

ย ย ย  $oldentry = @(bcdedit /enum $guid)
ย ย ย  if (!$?) { throw "Bcdedit error: $bcd" }

ย ย ย  bcdedit /set $guid device "vhd=[locate]$Path"
ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย  bcdedit /set $guid osdevice "vhd=[locate]$Path"
ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย  if (!$Fresh) {
ย ย ย ย ย ย ย  bcdedit /set $guid detecthal yes
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย  }

ย ย ย  # Enable debugging.
ย ย ย  if ($BcdDebug) {
ย ย ย ย ย ย ย  bcdedit /set $guid debug yes
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย ย ย ย ย  bcdedit /set $guid bootdebug yes
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย  }
ย ย ย  if ($BcdEvent) {
ย ย ย ย ย ย ย  bcdedit /set $guid debug no
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย ย ย ย ย  bcdedit /set $guid event yes
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย  }
ย ย ย  bcdedit /set $guid inherit "{bootloadersettings}"
ย ย ย  if (!$?) { throw "Bcdedit error." }

ย ย ย  # enable Hyper-v start if it's installed
ย ย ย  bcdedit /set $guid hypervisorlaunchtype auto
ย ย ย  if (!$?) { throw "Bcdedit error." }

ย ย ย  # The more sane boot menu.
ย ย ย  bcdedit /set $guid bootmenupolicy Legacy
ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย  bcdedit /set $guid bootstatuspolicy DisplayBootFailures
ย ย ย  if (!$?) { throw "Bcdedit error." }

ย ย ย  # Other useful diagnostic settings
ย ย ย  if ($Diagnose) {
ย ย ย ย ย ย ย  bcdedit /set $guid bootlog yes
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย ย ย ย ย  bcdedit /set $guid sos on
ย ย ย ย ย ย ย  if (!$?) { throw "Bcdedit error." }
ย ย ย  }

ย ย ย  # This is strictly needed only for CSS but doesn't hurt on other SKUs,
ย ย ย  # must use the path with "Boot", but preserve .exe vs .efi.
ย ย ย  $oldpath = $oldentry | ? { $_ -match "^path " } | % { $_ -replace "^path *","" }
ย ย ย  if (!$oldpath) {
ย ย ย ย ย ย ย  throw "The current BCD entry doesn't have a path value???"
ย ย ย  }
ย ย ย  $leaf = Split-Path -Leaf $oldpath

ย ย ย  bcdedit /set $guid path "WindowsSystem32Boot$leaf"
ย ย ย  if (!$?) { throw "Bcdedit error." }

ย ย ย  # Print the settings after editing.
ย ย ย  bcdedit /enum $guid
}
Export-ModuleMember -Function Add-BcdVhd
โ†ง
โ†ง

expect in PowerShell

$
0
0

Like the other text tools Iโ€™ve published here, this one is notย a fullย analog of the Unix tool.ย It does only the very basic thing that is sufficient in many cases. It reads the output from a background job looking for patterns. This is a very typical thing if you want to instruct some system do some action (though WMI or such) then look at its responses or logs to make sure that the action was completed before starting a new one.

Itโ€™s used like this:

# Suppose that the job that will be sending the output $myjob has been somehow created.
$ebuf = New-ExpectBuffer $myjob $LogFile
$line = Wait-ExpectJob -Buf $ebuf -Pattern "some .* text"
...
Skip-ExpectJob -Buf $ebuf -WaitStop

New-Expect buffer creates an expect object. It takes the job to read from, and the file name to write the received data to (which can be later used to debug any unexpected issues). It can do a couple of other tricks too: If the job is $null, then it will read the input from the file instead. The reading from the file is not very smart, the file is read just once. This is intended for testing the new patterns on a results of a previous actual expect. The second trick is thatย this whole set of fucntionsย auto-detects and corrects the corruption from the Unicode mistreatment.

Wait-ExpectJob polls the output of the job until it either gets a line with the pattern or a timeout expires or the job exits. The timeout and polling frequency can be specified in the parameters. A gross simplification here is that unlike the real expect, only one job is polled at a time. It would be trivial to extend to multiple buffers and multiple patterns, itโ€™s just that in reality so far Iโ€™ve needed only the very basic functionality. this function returns the line that contained the pattern, so that it can be examined further.

Skip-ExpectJobโ€™s first purpose is to skip (but write into the log file) any input received so far. This allows you to skip over the repeated patterns in the output before sending the next request. This is not completely fool-proof but with the judiciously used timeouts is good enough. The second purpose for it is to wait for the job to exit, with the flag -WaitStop. In the second use it just makes sure that by the time it returns the job had exited and all its output was logged. The second use also has a timeout.

Thatโ€™s basically it, here is the implementation (relying on my other text tools):

function New-ExpectBuffer
{
<#
.SYNOPSIS
Create a buffer object (returned) that would keep the data for
expecting the patterns in the job's output.
#>
ย ย ย  param(
ย ย ย ย ย ย ย  ## The job object to receive from.
ย ย ย ย ย ย ย  ## May be $null, then the data will be read from the file.
ย ย ย ย ย ย ย  $Job,
ย ย ย ย ย ย ย  ## Log file name to append the received data to (with a job)
ย ย ย ย ย ย ย  ## or read the data from (without a job).
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  $LogFile,
ย ย ย ย ย ย ย  ## Treat the input as Unicode corrupted by PowerShell,
ย ย ย ย ย ย ย  ## don't try to auto-detect.
ย ย ย ย ย ย ย  [switch] $Unicode
ย ย ย  )
ย ย ย  $result = @{
ย ย ย ย ย ย ย  job = $Job;
ย ย ย ย ย ย ย  logfile = $LogFile;
ย ย ย ย ย ย ย  buf = New-Object System.Collections.Queue;
ย ย ย ย ย ย ย  detect = (!$Unicode);
ย ย ย  }
ย ย ย  if (!$Job) {
ย ย ย ย ย ย ย  $data = (Get-Content $LogFile | ConvertFrom-Unicode -AutoDetect:$result.detect)
ย ย ย ย ย ย ย  if ($data) { 
ย ย ย ย ย ย ย ย ย ย ย  foreach ($val in $data) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  $result.buf.enqueue($val)
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }
ย ย ย  }
ย ย ย  $result
}

function Wait-ExpectJob
{
<#
.SYNOPSIS
Keep receiving output from a background job until it matches a pattern.
The output will be appended to the log file as it's received.
When a match is found, the line with it will be returned as the result.

The wait may be limited by a timeout. If the match is not received within
the timeout, throws an error (unless the option -Quiet is used, then
just returns).

If the job completes without matching the pattern, the reaction is the same
as on the timeout.
#>
ย ย ย  [CmdletBinding()]
ย ย ย  param(
ย ย ย ย ย ย ย  ## The buffer that keeps the job reference and the unmatched lines
ย ย ย ย ย ย ย  ## (as created with New-ExpectBuffer).
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  $Buf,
ย ย ย ย ย ย ย  ## Pattern (as for -match) to wait for.
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  $Pattern,
ย ย ย ย ย ย ย  ## Timeout, in fractional seconds. If $null, waits forever.
ย ย ย ย ย ย ย  [double] $Timeout = 10.,
ย ย ย ย ย ย ย  ## When the timeout expires, don't throw but just return nothing.
ย ย ย ย ย ย ย  [switch] $Quiet,
ย ย ย ย ย ย ย  ## Time in milliseconds for sleeping between the attempts.
ย ย ย ย ย ย ย  ## If the timeout is smaller than the step, the step will automatically
ย ย ย ย ย ย ย  ## be reduced to the size of timeout.
ย ย ย ย ย ย ย  [int] $StepMsec = 100
ย ย ย  )
ย ย ย  
ย ย ย  $deadline = $null
ย ย ย  if ($Timeout -ne $null) {
ย ย ย ย ย ย ย  $deadline = (Get-Date).ToFileTime();
ย ย ย ย ย ย ย  $deadline += [int64]($Timeout * (1000 * 1000 * 10))
ย ย ย  }

ย ย ย  while ($true) {
ย ย ย ย ย ย ย  while ($Buf.buf.Count -ne 0) {
ย ย ย ย ย ย ย ย ย ย ย  $val = $Buf.buf.Dequeue();
ย ย ย ย ย ย ย ย ย ย ย  if ($val -match $Pattern) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return $val
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  if (!$Buf.job) {
ย ย ย ย ย ย ย ย ย ย ย  if ($Quiet) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return
ย ย ย ย ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  throw "The pattern '$Pattern' was not found in the file '$($Buf.logfile)"
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  $data = (Receive-Job $Buf.job | ConvertFrom-Unicode -AutoDetect:$Buf.detect)
ย ย ย ย ย ย ย  Write-Verbose "Job sent lines:`r`n$data"
ย ย ย ย ย ย ย  if ($data) { 
ย ย ย ย ย ย ย ย ย ย ย  foreach ($val in $data) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  $Buf.buf.enqueue($val)
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  # Write the output to file as it's received, not as it's matched,
ย ย ย ย ย ย ย ย ย ย ย  # for the easier diagnostics of things that get mismatched.
ย ย ย ย ย ย ย ย ย ย ย  $data | Add-Content $Buf.logfile
ย ย ย ย ย ย ย ย ย ย ย  continue
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย  if (!($Buf.job.State -in ("Running", "Stopping"))) {
ย ย ย ย ย ย ย ย ย ย ย  if ($Quiet) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  Write-Verbose "Job found stopped"
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return
ย ย ย ย ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  throw "The pattern '$Pattern' was not received until the job exited"
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย  if ($deadline -ne $null) {
ย ย ย ย ย ย ย ย ย ย ย  $now = (Get-Date).ToFileTime();
ย ย ย ย ย ย ย ย ย ย ย  if ($now -ge $deadline) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  if ($Quiet) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  Write-Verbose "Job reading deadline expired"
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  throw "The pattern '$Pattern' was not received within $Timeout seconds"
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย ย ย ย ย  $sleepmsec = ($deadline - $now) / (1000 * 10)
ย ย ย ย ย ย ย ย ย ย ย  if ($sleepmsec -eq 0) { $sleepmsec = 1 }
ย ย ย ย ย ย ย ย ย ย ย  if ($sleepmsec -gt $StepMsec) { $sleepmsec = $StepMsec }
ย ย ย ย ย ย ย ย ย ย ย  Sleep -Milliseconds $sleepmsec
ย ย ย ย ย ย ย  }
ย ย ย  }
}

function Skip-ExpectJob
{
<#
.SYNOPSIS
Receive whetever available output from a background job without any
pattern matching.

The output will be appended to the log file as it's received.

Optionally, may wait for the job completion first.
The wait may be limited by a timeout. If the match is not received within
the timeout, throws an error (unless the option -Quiet is used, then
just returns).
#>
ย ย ย  param(
ย ย ย ย ย ย ย  ## The buffer that keeps the job reference and the unmatched lines
ย ย ย ย ย ย ย  ## (as created with New-ExpectBuffer).
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  $Buf,
ย ย ย ย ย ย ย  ## Wait for the job to stop before skipping the output.
ย ย ย ย ย ย ย  ## This guarantees that all the job's output is written to the log file.
ย ย ย ย ย ย ย  [switch] $WaitStop,
ย ย ย ย ย ย ย  ## Timeout, seconds. If $null and requested to wait, waits forever.
ย ย ย ย ย ย ย  [int32] $Timeout = 10,
ย ย ย ย ย ย ย  ## When the timeout expires, don't throw but just return nothing.
ย ย ย ย ย ย ย  [switch] $Quiet
ย ย ย  )

ย ย ย  if ($WaitStop) {
ย ย ย ย ย ย ย  Wait-Job -Job $Buf.job -Timeout $Timeout
ย ย ย  }

ย ย ย  Receive-Job $Buf.job | ConvertFrom-Unicode -AutoDetect:$Buf.detect | Add-Content $Buf.logfile

ย ย ย  if ($WaitStop) {
ย ย ย ย ย ย ย  if (!($Buf.job.State -in ("Stopped", "Completed"))) {
ย ย ย ย ย ย ย ย ย ย ย  if ($Quiet) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return
ย ย ย ย ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  throw "The job didn't stop within $Timeout seconds"
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }
ย ย ย  }
}

ย 

ย 

โ†ง

AX โ€“ Cรณmo incluir Valores de Dimensiรณn en la consulta Estadรญsticas de Control Presupuestario

$
0
0

INTRODUCCIร“N

El control de presupuesto es una validaciรณn que permite revisar que haya suficientes fondos disponibles para realizar compras. De manera que, en caso de no existir presupuesto suficiente para realizar una determinada compra, Microsoft Dynamics AX entrega un mensaje indicando la falta de fondos para una determinada Cuenta contable y sus dimensiones financieras.

Para poder dar seguimiento al Presupuesto en Microsoft Dynamics AX se tienen diferentes herramientas de consulta. Una de ellas es la consulta โ€˜Estadรญstica de Control Presupuestarioโ€™ [Imagen 1 โ€“ Estadรญstica de Control Presupuestario] la cual permite conocer: Fondos presupuestarios disponibles, Presupuesto total revisado, Cargos reales totales, Reservas de presupuesto para reservas de cargo y Reservas de presupuesto para pre-reservas de cargo.

ย 

Imagen 1 โ€“ Estadรญstica de Control Presupuestario

ย 

Ahora bien, considere que los valores de dimensiรณn que se despliegan para la opciรณn Valores de dimensiรณn [Imagen 1 โ€“ Estadรญstica de Control Presupuestario], concuerdan con los Criterios especificados en la Configuraciรณn del control presupuestario โ€“ Definir reglas de control presupuestario, ya que es aquรญ donde se definen las combinaciones de dimensiones financieras para el control presupuestario.

ย 

DEMOSTRACIร“N

A continuaciรณn, se realiza un ejercicio para demostrar lo anterior:

ย 

Observe en los Criterios de cuenta contable definidos en la Configuraciรณn del control presupuestario โ€“ Definir reglas de control presupuestario (Ruta. Gestiรณn presupuestaria > Configurar > Control presupuestario) [Imagen 2 โ€“ Configuraciรณn de control presupuestario], se ha especificado
un rango de cuentas de la 601200 a la 601400.

Imagen 2 โ€“ Configuraciรณn de control presupuestario

ย 

En consecuencia, los Valores de dimensiรณn que se observan para la consulta Estadรญsticas de control presupuestario (Ruta. Gestiรณn presupuestaria > Consultas y reportes > Control presupuestario) [Imagen 3 โ€“ Valores de dimensiรณn en Estadรญsticas de control presupuestario] inician desde la cuenta contable 601200 en adelante.

ย 

Imagen 3 โ€“ Valores de dimensiรณn en Estadรญsticas de control presupuestario

ย 

Ahora bien, si se amplรญa el rango de cuentas contables a considerarse en las Reglas de control presupuestario
[Imagen 4 โ€“ Configuraciรณn de control presupuestario] para iniciar desde la cuenta contable 500140,

ย 

Imagen 4 โ€“ Configuraciรณn de control presupuestario

ย 

entonces, los Valores de dimensiรณn que se tienen para las Estadรญsticas de control presupuestario, comenzarรกn desde la cuenta contable 500140 [Imagen 5 โ€“ Estadรญsticas de control presupuestario]

ย 

Imagen 5 โ€“ Estadรญsticas de control presupuestario

ย 

Referencias:

Budget control: Overview and configuration
https://ax.help.dynamics.com/en/wiki/budget-control-overview-and-configuration/

Budget control statistics by period page
https://ax.help.dynamics.com/en/wiki/budget-control-statistics-by-period-page-field-descriptions/

ย 

ย 

Para M

โ†ง

reading the ETW events in PowerShell

$
0
0

When testing or otherwise controlling a service, you need to read its log that gets written in the form of ETW events. There is the basic cmdlet Get-WinEvent that does this but with it you canโ€™t just read the events continuously. Instead you have to keep polling and connecting the new events to the previous ones. I want to show the code that does this polling.

The basic use that starts this reading in a job whose output can be sent into expect is like this:

ย ย ย  $col_job = Start-Job -Name $LogJobName -ScriptBlock {
ย ย ย ย ย ย ย  param($module)
ย ย ย ย ย ย ย  Import-Moduleย $module
ย ย ย ย ย ย ย  # -Nprev guards against the service starting earlier than the poller
ย ย ย ย ย ย ย  Read-WinEvents -LogName Microsoft-Windows-BootEvent-Collector/Admin -Nprev 1000 | % {
ย ย ย ย ย ย ย ย ย ย ย  "$($_.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss.fffffff')) $($_.Message)"
ย ย ย ย ย ย ย  }
ย ย ย  } -Args @("myscriptdirTextTools.psm1")

The job starting itself is a bit convoluted because the interpreterย in the job doesnโ€™t inherit anything at all from the current interpreter. All it gets is literally its arguments. So to use a function from a module, that module has to be imported explicitly from the code in the job.

The reading of events is pretty easy โ€“ just give it the ETWย log name. If you donโ€™t care about the events that might be in the log from before, thatโ€™s it. If you do care about the previous events (such as if you are just starting the service and want to see all the events it had sent since the start), the parameter -Nprev says that you want to see up to this number of the previously logged events. This isย more reliableย than trying to start the log reading job first and then the service.

Of course, if youโ€™ve been repeatedly stopping and starting the service, the log would also contain the events from the previous runs. Thatโ€™s why the limit N is useful, and also you can clean the event buffer in ETW with

wevtutil qe Microsoft-Windows-BootEvent-Collector/Admin

The default formatting of the event objects to strings is not very useful, so this example does its own formatting.

After youโ€™re done reading the events, you can just kill the job. The proper sequence for it together with expect would be:

Stop-Job $col_job
Skip-ExpectJob -Timeout $tout -Buf $col_buf -WaitStop
Remove-Job $col_job

And here is the implementation:

function Get-WinEventSafe
{
<#
.SYNOPSIS
Wrapper over Get-WinEvent that doesn't throw if no events are available.

Using -ea SilentlyContinue is still a good idea because PowerShell chokes
on the strings containing the '%'.
#>
ย ย ย  try {
ย ย ย ย ย ย ย  Get-WinEvent @args
ย ย ย  } catch {
ย ย ย ย ย ย ย  if ($_.FullyQualifiedErrorId -ne "NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand") {
ย ย ย ย ย ย ย ย ย ย ย  throw
ย ย ย ย ย ย ย  }
ย ย ย  }
}

function Get-WinEventsAfter
{
<#
.SYNOPSIS
Do one poll of an online ETW log, returning the events received after
the last previous event.
#>
ย ย ย  [CmdletBinding()]
ย ย ย  param(
ย ย ย ย ย ย ย  ## Name of the log to read the events from.
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  [string] $LogName,
ย ย ย ย ย ย ย  ## The last previous event, get the events after it.
ย ย ย ย ย ย ย  [System.Diagnostics.Eventing.Reader.EventLogRecord] $Prev,
ย ย ย ย ย ย ย  ## The initial scoop size for reading the events, if that scoop doesn't
ย ย ย ย ย ย ย  ## reach the previous event, the scoop will be grown twice on each
ย ย ย ย ย ย ย  ## attempt. If there is no previous event, all the available events will be returned.
ย ย ย ย ย ย ย  [uint32] $Scoop = 128
ย ย ย  )

ย ย ย  if ($Prev -eq $null) {
ย ย ย ย ย ย ย  # No previous record, just return everything
ย ย ย ย ย ย ย  Get-WinEventSafe -LogName $LogName -Oldest -ea SilentlyContinue
ย ย ย ย ย ย ย  return
ย ย ย  }

ย ย ย  $ptime = $Prev.TimeCreated

ย ย ย  for (;; $Scoop *= 2) {
ย ย ย ย ย ย ย  # The events come out in the reverse order
ย ย ย ย ย ย ย  $ev = @(Get-WinEventSafe -LogName $LogName -MaxEvents $Scoop -ea SilentlyContinue)
ย ย ย ย ย ย ย  if ($ev.Count -eq 0) {
ย ย ย ย ย ย ย ย ย ย ย  return # no events, nothing to do
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  $last = $ev.Count - 1
ย ย ย ย ย ย ย  if ($ev.Count -ne $Scoop -or $ev[$last].TimeCreated -lt $Prev.TimeCreated) {
ย ย ย ย ย ย ย ย ย ย ย  # the scoop goes past the previous event, find the boundary in it
ย ย ย ย ย ย ย ย ย ย ย  for (; ; --$last) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  if ($last -lt 0) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return # no updates, return nothing
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }

ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  $etime = $ev[$last].TimeCreated
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  if ($etime -lt $ptime) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  continue
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  if ($etime -gt $ptime) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  break
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  if ($ev[$last].Message -eq $Prev.Message) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  --$last # skip the copy of the same event
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  if ($last -lt 0) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  return # no updates, return nothing
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  break
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย ย ย ย ย  $ev = $ev[0..$last]
ย ย ย ย ย ย ย ย ย ย ย  [array]::Reverse($ev) # in-place
ย ย ย ย ย ย ย ย ย ย ย  $ev
ย ย ย ย ย ย ย ย ย ย ย  return
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  # otherwise need to scoop more
ย ย ย  }
}

function Read-WinEvents
{
<#
.SYNOPSIS
Poll an online ETW log forever, until killed.
#>
ย ย ย  [CmdletBinding()]
ย ย ย  param(
ย ย ย ย ย ย ย  ## Name of the log to read the events from.
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  [string] $LogName,
ย ย ย ย ย ย ย  ## The poll period, in seconds, floating-point.
ย ย ย ย ย ย ย  [double] $Period = 1.,
ย ย ย ย ย ย ย  ## The initial scoop size for Get-WinEventsAfter.
ย ย ย ย ย ย ย  [uint32] $Scoop = 128,
ย ย ย ย ย ย ย  ## Number of previous records to return at the start.
ย ย ย ย ย ย ย  [uint32] $Nprev = 0
ย ย ย  )

ย ย ย  $prev = $null
ย ย ย  [int32] $msec = $Period * 1000

ย ย ย  $isVerbose = ($VerbosePreference -ne "SilentlyContinue")

ย ย ย  # read the initial records
ย ย ย  if ($Nprev -gt 0) {
ย ย ย ย ย ย ย  $ev = @(Get-WinEventSafe -LogName $LogName -MaxEvents $Nprev -ea SilentlyContinue)
ย ย ย ย ย ย ย  [array]::Reverse($ev) # in-place
ย ย ย ย ย ย ย  if ($isVebose)ย  {
ย ย ย ย ย ย ย ย ย ย ย  & {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  "Got the previous events:"
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  $ev | fl | Out-String
ย ย ย ย ย ย ย ย ย ย ย  } | Write-Verbose
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  $ev
ย ย ย ย ย ย ย  $prev = $ev[-1]
ย ย ย ย ย ย ย  $ev = @()
ย ย ย  } else {
ย ย ย ย ย ย ย  $ev = @(Get-WinEventSafe -LogName $LogName -MaxEvents 1 -ea SilentlyContinue)
ย ย ย ย ย ย ย  & {
ย ย ย ย ย ย ย ย ย ย ย  "Got the previous event:"
ย ย ย ย ย ย ย ย ย ย ย  $ev | fl | Out-String
ย ย ย ย ย ย ย  } | Write-Verbose
ย ย ย ย ย ย ย  $prev = $ev[0]
ย ย ย  }

ย ย ย  for (;;) {
ย ย ย ย ย ย ย  Sleep -Milliseconds $msec
ย ย ย ย ย ย ย  $ev = @(Get-WinEventsAfter -LogName $LogName -Prev $prev -Scoop $Scoop)
ย ย ย ย ย ย ย  & {
ย ย ย ย ย ย ย ย ย ย ย  "Got more events:"
ย ย ย ย ย ย ย ย ย ย ย  $ev | fl | Out-String
ย ย ย ย ย ย ย  } | Write-Verbose
ย ย ย ย ย ย ย  if ($ev) {
ย ย ย ย ย ย ย ย ย ย ย  $ev
ย ย ย ย ย ย ย ย ย ย ย  $prev = $ev[-1]
ย ย ย ย ย ย ย ย ย ย ย  $ev = @()
ย ย ย ย ย ย ย  }
ย ย ย  }
}

See Also: all the text tools

โ†ง

reporting the nested errors in PowerShell

$
0
0

A pretty typical pattern for PowerShell goes like this:

...allocate resource...
try {
ย  ... process resource ...
} finally {
ย  ...deallocate resource...
}

It makes sure that the resource gets properly deallocated even if the processing fails. However there is a problem in this pattern: if the finally block gets called on exception and the resource deallocation experiences an error for some reason and throws an exception, that exception will replace the first one. Youโ€™d see what failed in the deallocation but not what failed with the processing in the first place.

I want to share a few solutions for this problem that Iโ€™ve come with. The problem is two-prong: one part of it is the reporting of the nested errors, another one is collecting all the encountered errors which can then be built into a nested error.

As the reporting of the nested errors goes, the basic .NET exception has the provision for it but itโ€™s not so easy to use in practice because the PowerShell exception objects are wrappers around the .NET exceptions and carry the extra information: the PowerShell stack trace. The nesting shouldnโ€™t lose this stack trace.

So I wrote a function that does this, New-EvNest (you can think of the prefix โ€œEvโ€ as meaning โ€œerror valueโ€, although historically it was born for other reasons). The implementation of carrying of the stack trace has turned out to be pretty convoluted but the use is easy:

$combinedError = New-EvNest -Error $_ -Nested $InnerError

in some cases the outer error would be just a high-level text description, so there is a special form for that:

$combinedError = New-EvNest -Textย "Failed to process the resource" ย -Nested $InnerError

You can then re-throw the combined error:

throw $combinedError

Iโ€™ve also made a convenience function for re-throwing with an added description:

New-Rethrow -Textย "Failed to process the resource" ย -Nested $InnerError

And here is the implementation:

function New-EvNest
{
<#
.SYNOPSIS
Create a new error that wraps the existing one (but don't throw it).
#>
ย ย ย  [CmdletBinding(DefaultParameterSetName="Text")]
ย ย ย  param(
ย ย ย ย ย ย ย  ## Text of the wrapper message.
ย ย ย ย ย ย ย  [parameter(ParameterSetName="Text", Mandatory=$true, Position = 0)]
ย ย ย ย ย ย ย  [string] $Text,
ย ย ย ย ย ย ย  ## Alternatively, if combining two errors, the "outer"
ย ย ย ย ย ย ย  ## error. The text and the error location from it will be
ย ย ย ย ย ย ย  ## prepended to the combined information.
ย ย ย ย ย ย ย  [parameter(ParameterSetName="Object", Mandatory=$true)]
ย ย ย ย ย ย ย  [System.Management.Automation.ErrorRecord] $Error,
ย ย ย ย ย ย ย  ## The nested System.Management.Automation.ErrorRecord that
ย ย ย ย ย ย ย  ## was caught and needs re-throwing with an additional wrapper.
ย ย ย ย ย ย ย  [parameter(Mandatory=$true, Position = 1)]
ย ย ย ย ย ย ย  [System.Management.Automation.ErrorRecord] $Nested
ย ย ย  )

ย ย ย  if ($Error) {
ย ย ย ย ย ย ย  $Text = $Error.FullyQualifiedErrorId
ย ย ย ย ย ย ย  if ($Error.TargetObject -is [hashtable] -and $Error.TargetObject.stack) {
ย ย ย ย ย ย ย ย ย ย ย  $headpos = $Error.TargetObject.posinfo + "`r`n"
ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย  $headpos = $Error.InvocationInfo.PositionMessage + "`r`n"
ย ย ย ย ย ย ย  }
ย ย ย  }

ย ย ย  # The new exception will wrap the old one.
ย ย ย  $exc = New-Object System.Management.Automation.RuntimeException @($Text, $Nested.Exception)

ย ย ย  # The script stack is not in the Exception (the nested part), so it needs to be carried through
ย ย ย  # the ErrorRecord with a hack. The innermost stack is carried through the whole
ย ย ย  # chain because it's the deepest one.
ย ย ย  # The carrying happens by encoding the original stack as the TargetObject.
ย ย ย  if ($Nested.TargetObject -is [hashtable] -and $Nested.TargetObject.stack) {
ย ย ย ย ย ย ย  if ($headpos) {
ย ย ย ย ย ย ย ย ย ย ย  $wrapstack = @{
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  stack = $Nested.TargetObject.stack;
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  posinfo = $headpos + $Nested.TargetObject.posinfo;
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย  $wrapstack = $Nested.TargetObject
ย ย ย ย ย ย ย  }
ย ย ย  } elseif($Nested.ScriptStackTrace) {
ย ย ย ย ย ย ย  $wrapstack = @{
ย ย ย ย ย ย ย ย ย ย ย  stack = $Nested.ScriptStackTrace;
ย ย ย ย ย ย ย ย ย ย ย  posinfo = $headpos + $Nested.InvocationInfo.PositionMessage;
ย ย ย ย ย ย ย  }
ย ย ย  } else {
ย ย ย ย ย ย ย  if ($headpos) {
ย ย ย ย ย ย ย ย ย ย ย  $wrapstack = $Error.TargetObject
ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย  $wrapstack = $null
ย ย ย ย ย ย ย  }
ย ย ย  }

ย ย ย  # The new error record will wrap the exception and carry over the stack trace
ย ย ย  # from the old one, which unfortunately can't be just wrapped.
ย ย ย  return (New-Object System.Management.Automation.ErrorRecord @($exc,
ย ย ย ย ย ย ย  "$Text`r`n$($Nested.FullyQualifiedErrorId)", # not sure if this is the best idea, the arbitrary text goes against the
ย ย ย ย ย ย ย  # principles described in http://msdn.microsoft.com/en-us/library/ms714465%28v=vs.85%29.aspx
ย ย ย ย ย ย ย  # but this is the same as done by the {throw $Text},
ย ย ย ย ย ย ย  # and it allows to get the errors printed more nicely even with the default handler
ย ย ย ย ย ย ย  "OperationStopped", # would be nice to have a separate category for wraps but for now
ย ย ย ย ย ย ย  # just do the same as {throw $Text}
ย ย ย ย ย ย ย  $wrapstack
ย ย ย  ))
}

function New-Rethrow
{
<#
.SYNOPSIS
Create a new error that wraps the existing one and throw it.
#>
ย ย ย  param(
ย ย ย ย ย ย ย  ## Text of the wrapper message.
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  [string] $Text,
ย ย ย ย ย ย ย  ## The nested System.Management.Automation.ErrorRecord that
ย ย ย ย ย ย ย  ## was caught and needs re-throwing with an additional wrapper.
ย ย ย ย ย ย ย  [parameter(Mandatory=$true)]
ย ย ย ย ย ย ย  [System.Management.Automation.ErrorRecord] $Nested
ย ย ย  )
ย ย ย  throw (New-EvNest $Text $Nested)
}
Set-Alias rethrow New-Rethrow

The information about the PowerShell call stack is carried through the whole nesting sequence from the innermost object to the outernost object.

Now we come to the second prong, catching the errors. The simple approach would be to do:

...allocate resource...
try {
ย  ... process resource ...
} finally {
ย  try {
ย ย ย  ...deallocate resource...
ย  } catch {
ย ย ย ย throw (New-EvNest -Error $_ -Nexted $prevException)
ย  }
}

except that in finally we donโ€™t know if there was a nested exception or not. So the code grows to:

...allocate resource...
$prevException = $null
try {
ย  ... process resource ...
}ย catch {
ย  $prevException = $_
} finally {
ย  try {
ย ย ย  ...deallocate resource...
ย  } catch {
ย ย ย  if ($prevException) {
ย  ย ย ย ย throw (New-EvNest -Error $_ -Nexted $prevException)
ย ย ย  } elseย {
ย ย ย ย ย  throw $_
ย ย ย  }
ย  }
}

You can see that this quickly becomes not very manageable, especially if you have multiple nested resources. So my next approach was to wrtite one more helper function Rethrow-ErrorList and use it in a pattern like this:

ย ย ย  $errors = @()
ย ย ย  # nest try/finally as much as needed, as long as each try goes
ย ย ย  # with this kind of catch; the outermost "finally" block must
ย ย ย  # be wrapped in a plain try/catch
ย ย ย  try {
ย ย ย ย ย ย ย  try {
ย ย ย ย ย ย ย ย ย ย ย  ...
ย ย ย ย ย ย ย  } catch {
ย ย ย ย ย ย ย ย ย ย ย  $errors = $errors + @($_)
ย ย ย ย ย ย ย  } finally {
ย ย ย ย ย ย ย ย ย ย ย  ...
ย ย ย ย ย ย ย  }
ย ย ย  } catch {
ย ย ย ย ย ย ย  $errors = $errors + @($_)
ย ย ย  }
ย ย ย  Rethrow-ErrorList $errors

Rethrow-ErrorList throws if the list of errors is not empty, combining them all into one error. This pattern also nests easily: the nested instances keep using the same $errors, and all the exceptions get neatly collected in it along the way. Here is the implementation:

function Publish-ErrorList
{
<#
.SYNOPSIS
If the list of errors collected in the try-finally sequence is not empty,
report it in the verbose channel, build a combined error out of them,
and throw it. If the list is empty, does nothing.

An alternative way to handle the errors is Undo-OnError.

The typical usage pattern is:

ย ย ย  $errors = @()
ย ย ย  # nest try/finally as much as needed, as long as each try goes
ย ย ย  # with this kind of catch; the outermost "finally" block must
ย ย ย  # be wrapped in a plain try/catch
ย ย ย  try {
ย ย ย ย ย ย ย  try {
ย ย ย ย ย ย ย ย ย ย ย  ...
ย ย ย ย ย ย ย  } catch {
ย ย ย ย ย ย ย ย ย ย ย  $errors = $errors + @($_)
ย ย ย ย ย ย ย  } finally {
ย ย ย ย ย ย ย ย ย ย ย  ...
ย ย ย ย ย ย ย  }
ย ย ย  } catch {
ย ย ย ย ย ย ย  $errors = $errors + @($_)
ย ย ย  }
ย ย ย  Rethrow-ErrorList $errors

#>
ย ย ย  [CmdletBinding()]
ย ย ย  param(
ย ย ย ย ย ย ย  ## An array of error objects to test and rethrow.
ย ย ย ย ย ย ย  [array] $Errors
ย ย ย  )
ย ย ย  if ($Errors) {
ย ย ย ย ย ย ย  $vp = $VerbosePreference
ย ย ย ย ย ย ย  $VerbosePreference = "Continue"
ย ย ย ย ย ย ย  Write-Verbose "Caught the errors:"
ย ย ย ย ย ย ย  $Errors | fl | Out-String | Write-Verbose
ย ย ย ย ย ย ย  $VerbosePreference = $vp

ย ย ย ย ย ย ย  if ($Errors.Count -gt 1) {
ย ย ย ย ย ย ย ย ย ย ย  $rethrow = $Errors[0]
ย ย ย ย ย ย ย ย ย ย ย  for ($i = 1; $i -lt $Errors.Count; $i++) {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  $rethrow = New-EvNest -Error ($Errors[$i]) -Nested $rethrow
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  } else {
ย ย ย ย ย ย ย ย ย ย ย  $rethrow = $Errors[0]
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  throw $rethrow
ย ย ย  }
}
Set-Alias Rethrow-ErrorList Publish-ErrorList

After that Iโ€™ve tried one more approach. Itโ€™s possible to pass the script blocks as parameters to a function, so a function can pretend to be a bit like a statement:

Undo-OnError -Do {
  ...allocate resource...
}ย -Try {
ย  ... process resource ...
}ย -Undo {
ย  ...deallocate resource...
}

Looked cute in theory but in practice it had hit the snag that the script blocks in PowerShell are not closures. If some variables get assigned inside script blocks, theyโ€™re invisible outside these script blocks, and thatโ€™s a major pain here because youโ€™d usually place the allocated resource into some variable and then read that variable during processing and deallocation. Of course, with the script blocks being separate here, the variables assigned during allocation would get lost. Itโ€™s possible to work around this issue by making a surrogate scope in a hash table:

$scope = @{}
Undo-OnError -Do {
  $scope.resource = ...allocate resource ...
}ย -Try {
  ... process resource from $scope.resource ...
}ย -Undo {
  ...deallocate resource from $scope.resource ...
}

So it kind of works but unless you do a lot of nesting, Iโ€™m not sure that itโ€™s a whole lot better than the pattern with the Rethrow-ErrorList. If this were made into a PowerShell statement that makes a proper scope management, it could work a lot better. Or I guess even better, the try/finally statement could be extended to re-throw a nested exception if both try and finally parts throw. And the throw statement could be extended to create a nested exception if its argument is an array. This would give all the benefits without any changes to the language.

Here is the implementation:

function Undo-OnError
{
<#
.SYNOPSIS
A wrapper of try blocks. Do some action, then execute some code that
uses it, and then undo this action. The undoing is executed even if an
error gets thrown. It's essentially a "finally" block, only with the
nicer nested reporting of errors.

An alternative way to handle the errors is Rethrow-ErrorList.
#>
ย ย ย  param(
ย ย ย ย ย ย ย  ## The initial action to do.
ย ย ย ย ย ย ย  [scriptblock] $Do,
ย ย ย ย ย ย ย  ## The code that uses the action from -Do. Essentially, the "try" block.
ย ย ย ย ย ย ย  [scriptblock] $Try,
ย ย ย ย ย ย ย  ## The undoing of the initial action (like the "finally" block).
ย ย ย ย ย ย ย  [scriptblock] $Undo,
ย ย ย ย ย ย ย  ## Flag: call the action -Undo even if the action -Do itself throws
ย ย ย ย ย ย ย  ## an exception (useful if the action in -Do is not really atomic can
ย ย ย ย ย ย ย  ## can leave things in an inconsistent state that requires cleaning).
ย ย ย ย ย ย ย  [switch] $UndoSelf
ย ย ย  )

ย ย ย  try {
ย ย ย ย ย ย ย  &$Do
ย ย ย  } catch {
ย ย ย ย ย ย ย  if ($UndoSelf) {
ย ย ย ย ย ย ย ย ย ย ย  $nested = $_
ย ย ย ย ย ย ย ย ย ย ย  try {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  &$Undo
ย ย ย ย ย ย ย ย ย ย ย  } catch {
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  throw (New-EvNest -Error $_ $nested)
ย ย ย ย ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  throw
ย ย ย  }
ย ย ย  try {
ย ย ย ย ย ย ย  &$Try
ย ย ย  } catch {
ย ย ย ย ย ย ย  $nested = $_
ย ย ย ย ย ย ย  try {
ย ย ย ย ย ย ย ย ย ย ย  &$Undo
ย ย ย ย ย ย ย  } catch {
ย ย ย ย ย ย ย ย ย ย ย  throw (New-EvNest -Error $_ $nested)
ย ย ย ย ย ย ย  }
ย ย ย ย ย ย ย  throw
ย ย ย  }
ย ย ย  &$Undo
}

ย 

โ†ง
โ†ง

Internet Explorer 11 hosting a Drag & Drop ActiveX control advances from onDragEnter to OnDrop instead of onDragEnter -> onDragOver on Windows 10 x86 and x64 iexplore processes.

$
0
0
The issue as stated in the title is reproducible on fast dragging. See details below.
This happens only when the ActiveX is hosted in IE11. The issue does not occur when the same ActiveX control is hosted on a Win Form application.
To repro the issue here is what you need to do:
Please refer to the attached sample ActiveX control named:ย myactivexcontrol
Build & register MyActiveXControl. I have also attached myactivexcontrol_ocx which you can directly register & use.
Place any text file named ReadMe.txt in C:Temp folder. Of course you can change the location from the ActiveX code.
Createย a sample HTML file named TestPage.htmlย andย open this in IE 11 to test the issue.
Here are the contents of the HTML file:
<HTML>
<HEAD>
<TITLE>Drag & Drop Test</TITLE>
</HEAD>
<BODY>
<CENTER>
<!โ€“
This is the key to the example.ย  The OBJECT
tag is a new tag used to download ActiveX
components.ย  Once the ActiveX component is available,
you can set its properties by using the PARAM tag.
โ€“>
<OBJECT
CLASSID=โ€clsid:90EDC5CE-75EE-47F2-AB0E-7E7444FD9257โ€ณ
ID=โ€MYACTIVEXCONTROL.MyActiveXControlCtrl.1โ€ณ
</OBJECT>
<ondragover=โ€window.event.returnValue=false;โ€>
</CENTER>
</BODY>
</HTML>

The ActiveX is the one as shown below in an ellipse (which I draw in CMyActiveXControlCtrl::OnDraw() ). I associate a simple text file with the ActiveX window (see CMyActiveXControlCtrl::OnLButtonDown() ). You need to drag that text file from the ActiveX to say Desktop.ย 

snip1

In fast dragging (even if left mouse button is down) we see only this log:

[3508] grfKeyState is: 0
[3508] DRAGDROP_S_DROP <= The files drops to the same IE window.
grfKeyState never changed to 1 โ€“ which is the issue. This however does not happen on Windows 7 OS (32 bit & 64 bit both).

grfKeyState changes to 1 only when you click on the ActiveX and wait for the small arrow (shown below) to appear. This however is not required on Windows 7 OS.
snip2
Is there a workaround that exists?
Yes. This is how I fixed it and has worked from Windows 7 to Windows 10.
Please refer to the attached sample ActiveX control named: MyActiveXControl.ZIP
File Name: DropSource.h
Function Name: HRESULT CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
WORKAROUND 1
============
Instead of relying on grfKeyState, I checked the mouse button state using GetKeyState() API and return DRAGDROP_S_DROP when the mouse button is released. I have tested it and it works fine.// Modified QueryContinueDrag() codeHRESULT CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
DWORD my_grfKeyStateย  = 0;
// If the high-order bit is 1, the key is down; otherwise, it is up.
if((GetKeyState(VK_LBUTTON) & 0x80) != 0)
{
my_grfKeyState = 1;
}

TCHAR buffer[100];
swprintf_s(buffer, 100, Lโ€grfKeyState is: %dโ€, grfKeyState);

::OutputDebugString(buffer);
swprintf_s(buffer, 100, Lโ€my_grfKeyState is: %dโ€, my_grfKeyState);
::OutputDebugString(buffer);

if (fEscapePressed)
{
::OutputDebugString(Lโ€DRAGDROP_S_CANCELโ€);
return DRAGDROP_S_CANCEL;
}

if (!(my_grfKeyState & (MK_LBUTTON | MK_RBUTTON)))
{
::OutputDebugString(Lโ€DRAGDROP_S_DROPโ€);
return DRAGDROP_S_DROP;
}

::OutputDebugString(Lโ€S_OKโ€);
return S_OK;
}

WORKAROUND 2
============
I made some changes in CDropSource::QueryContinueDrag() (see below) to test PeekMessage(). PeekMessage seems to be working fine. So the only anomaly what we see in case of the ActiveX hosted in IE11, is for the first time when grfKeyState never changes to 1 from 0.
if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) never becomes TRUE.
HRESULT CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
TCHAR buffer[100];
MSG msg;
DWORD my_grfKeyStateย  = 0;
ย ย ย  swprintf_s(buffer, 100, Lโ€my_grfKeyState before PeekMessage is: %dโ€, my_grfKeyState);
::OutputDebugString(buffer);
//auto HaveAnyMouseMessages = [&]() -> BOOL
//{
//ย ย ย  return PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
//};
ย ย ย  // Busy wait until a mouse or escape message is in the queue
while (!PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
{
// Note: all keyboard messages except escape are tossed. This is
// fairly reasonable since the user has to be holding the left
// mouse button down at this point. They canโ€™t really be doing
// too much data input one handed.
if ((PeekMessage(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE)
|| PeekMessage(&msg, 0, WM_SYSKEYDOWN, WM_SYSKEYDOWN, PM_REMOVE))
&& msg.wParam == VK_ESCAPE)
{
fEscapePressed = TRUE;
break;
}
}
ย ย ย  if (!fEscapePressed)
{
if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
{
my_grfKeyState = GetControlKeysStateOfParam(msg.wParam);
swprintf_s(buffer, 100, Lโ€my_grfKeyState after PeekMessage is: %dโ€, my_grfKeyState);
::OutputDebugString(buffer);
}
}
ย ย ย  DWORD my_grfKeyState1ย  = 0;
if((GetKeyState(VK_LBUTTON) & 0x80) != 0)
{
my_grfKeyState1 = 1;
}
//// DWORD my_grfKeyState = GetAsyncKeyState(VK_LBUTTON); //GetKeyState(VK_LBUTTON);
ย ย ย  swprintf_s(buffer, 100, Lโ€my_grfKeyState1 from GetKeyState() is: %dโ€, my_grfKeyState1);
::OutputDebugString(buffer);
//swprintf_s(buffer, 100, Lโ€my_grfKeyState is: %dโ€, my_grfKeyState);
//::OutputDebugString(buffer);if (fEscapePressed)
{
::OutputDebugString(Lโ€DRAGDROP_S_CANCELโ€);
return DRAGDROP_S_CANCEL;
}
ย ย ย  // if (!(my_grfKeyState & (MK_LBUTTON | MK_RBUTTON)))
// if(my_grfKeyState == 0 && grfKeyState == 0)
if (!(my_grfKeyState & (MK_LBUTTON | MK_RBUTTON)))
{
::OutputDebugString(Lโ€DRAGDROP_S_DROPโ€);
return DRAGDROP_S_DROP;
}
ย ย ย ย  ::OutputDebugString(Lโ€S_OKโ€);
return S_OK;
}
Output:
[8452] OnLButtonDown
[8452] GetUIObjectOfFile succeeded
[8452] DoDragDrop
[8452] my_grfKeyState before PeekMessage is: 0
[8452] my_grfKeyState after PeekMessage is: 1
[8452] my_grfKeyState1 from GetKeyState() is: 1
[8452] S_OK
[8452] my_grfKeyState before PeekMessage is: 0
[8452] my_grfKeyState1 from GetKeyState() is: 1
[8452] DRAGDROP_S_DROP
However we do have an official fix for this issue from Microsoft.
KB 3179574 (Link: https://support.microsoft.com/en-us/kb/3179574) โ€“ ย fixes the issue on Windows 8.1 .
Test Results
=========
Operating System: Windows 8.1 x64 (Version 6.3, Build: 9600)
ole32.dll version: 6.3.9600.18256
Issue exists with this version.
Downloaded https://support.microsoft.com/en-us/kb/3179574
Installed this KB. Restarted the machine.
ole32.dll version: 6.3.9600.18403
Issue not reproducible.
For Windows 10 and above OSโ€™s, apply KB 3201845 (Link: https://support.microsoft.com/en-us/kb/apply KB 3201845). This comes via the Windows Update. In the KB you will find a statement saying โ€œAddressed issue with OLE drag and drop that prevents users from downloading a SharePoint document library as a fileโ€.
โ†ง

Capturing Full User Mode Dumps & PerfView traces for troubleshooting high CPU & hang issues.

$
0
0

Please note: below are the steps for capturing traces and not the way to analyze them. It is very essential to capture right traces before analyzing them to find a root case, essentially for high CPU or troubleshooting a process hang.

In general, a dump is a process snapshot of its virtual memory at a single point in time. A one single user mode dump is not the appropriate way to analyze a hang or a high CPU scenario. We need multiple hang dumps captured in the overall time span or vicinity of the hang. Capturing PerfView traces at the time of the hang also makes sense.

DEBUGDIAG for Dump Capture

  • Debug Diagnostic tool download link: https://www.microsoft.com/en-us/download/details.aspx?id=49924
  • Install the MSI (download 64 bit MSI if your OS is 64 bit else the 32 bit MSI).
  • From the desktop click at START menu and search for DebugDiag2 Collection and run it.
  • Cancel the โ€œSelect Rule Typeโ€ dialog.

Go to Processes tab as shown in the screen shot below. During the slowness, hang or high CPU, select your process (for a Web application it would be w3wp.exe), right click and click at โ€œCreate FullUserdumpโ€. Repeat this at uniform intervals in the entire duration of the hang. For example if the process hangs now, start capturing dumps and capture say for example 5 dumps at 30 seconds or 60 seconds interval.ย This dump will give a discrete picture of theย process virtual memory at 5 different intervals and of course a better picture of the process โ€“ what itโ€™s threads were doing in the 150 seconds or 300 seconds discrete time frame.ย Default location of the dumps files: C:Program FilesDebugDiagLogsMisc

ย snip3

Alternatively, you can also automate the above process by going to the same Processes tab (shown in the screen shot above), right click the process (for which you would like to capture dumps) and select ย โ€œCreate Userdump Seriesโ€ฆโ€œ. Select/Adjust the options as shown in the screen shot below. It isย good to have Full UserDumps.

snip6

Default location of the dumps files: C:Program FilesDebugDiagLogsMisc

Post capturing the dumps, ZIP the Misc folder and upload it to the case workspace (if you are using Microsoft support) for sending it to the engineer working with you.

ย 

PERFVIEW

PerfView download location: https://www.microsoft.com/en-in/download/details.aspx?id=28567

Run PerfView.exe, follow the steps below during the high CPU or hang or process slowness:

At the time of the issue (when you see the slowness)

1.ย ย ย ย  Click at Collect Menu and select Collect option

2.ย ย ย ย  CHECK Zip, Merge, thread time check boxes as shown in the screen shot below.

snip4

3. If IIS is involved, expand the Advanced Options tab and select IIS checkbox as show in the screen shotย below and click at โ€œStart Collectionโ€ button to capture traces.

snip5

4. To stop collecting the traces (collect traces for few minutes), select โ€œStop Collectionโ€ from the same PerfView dialog and allow (meaning wait) the log capture to Merge (you can see that from the PerfView window status bar, flickering towards the right). Once the merge is complete you would noticeย files with names ending inย *.etl.zip on theย same folder from where you ran PerfView.ย Upload it to the case workspace (if you are using Microsoft support) for sending it to the engineer working with you.

ย 

โ†ง

How the OS behaves in deciding when to use an extra CPU?

$
0
0

I typically got this question from a customer who was explicitly trying to know: How the OS behaves in deciding when to use an extra CPU to process COM+ requests?

Ideally to answer this in one line I would have to say: there is no additional way for the OS to decide that a thread is a COM+ thread or a thread is from any other process for example say notepad.exe.

Please note: all threads from user mode processes are executing at PASSIVE_LEVEL. User-mode code executes at PASSIVE_LEVEL. This is the level at which threads run. In fact https://blogs.msdn.microsoft.com/doronh/2010/02/02/what-is-irql/ says: if you look at the specific definition of โ€œthreadโ€ in NT, it pretty much only covers code that runs in the context of a specific process, at PASSIVE_LEVEL or APC_LEVEL.

There is no separate distinction which the OS will make for a COM+ thread.

If you read through โ€œOperating System Conceptsโ€ & โ€œOperating System Concept Essentialsโ€ by Silberschatz and Galvin, it says:

Almost all processes alternate between two states in a continuing cycle:

โ€ข A CPU burst of performing calculations, and

โ€ข An I/O burst, waiting for data transfer in or out of the system.

CPU bursts vary from process to process, and from program to program, but an extensive study shows frequency patterns similar to the one shown in the diagram below:

<diagram snipped from the same OS book referred earlier>

ย snip7

From the task manager you can set the processor affinity of a process (see below) but the default is set for all. So by choosing any specific processor (choosing a subset) doesnโ€™t make computations fast.

ย snip8

You can even change the priority of a process from the task manager but it can make the system highly unstable. Ideally as said before:ย  There is no separate distinction which the OS will make for a COM+ thread. User-mode code executes at PASSIVE_LEVEL.

snip9

IMHO: the task manager (shown in the screen shot above) sets the priority class of process as discussed in https://msdn.microsoft.com/en-us/library/windows/desktop/ms685100(v=vs.85).aspx. Use HIGH_PRIORITY_CLASS with care. If a thread runs at the highest priority level for extended periods, other threads in the system will not get processor time. If several threads are set at high priority at the same time, the threads lose their effectiveness.

As the MSDN link says: You should almost never use REALTIME_PRIORITY_CLASS, because this interrupts system threads that manage mouse input, keyboard input, and background disk flushing. This class can be appropriate for applications that โ€œtalkโ€ directly to hardware or that perform brief tasks that should have limited interruptions.

โ†ง

[Sample Of Dec. 30] How to filter data in view model in Win 10 UWP apps

$
0
0
image
Dec.
30
image
image

Sample :ย https://code.msdn.microsoft.com/How-to-filter-data-in-view-4d83dd03

This sample demonstrates how to filter data in view model in Win 10 UWP apps.

image

You can find more code samples that demonstrate the most typical programming scenarios by usingย Microsoft All-In-One Code Framework Sample Browser or Sample Browser Visual Studio extension. They give you the flexibility to search samples, download samples on demand, manage the downloaded samples in a centralized place, and automatically be notified about sample updates. If it is the first time that you hear about Microsoft All-In-One Code Framework, please watch the introduction video on Microsoft Showcase, or read the introduction on our homepage http://1code.codeplex.com/.

โ†ง
โ†ง

Collecting diagnostics for WCF (hosted in IIS) & Web Service performance related issues

$
0
0

Say for example you are troubleshooting a high CPU or a slow response or a hang issue. For diagnostics collect the following from the server side:

  1. IIS Logs (Location: %SystemDrive%inetpublogsLogFiles)
  2. FREB traces (see steps below)
  3. PerfView traces (see steps below)
  4. Dumps of the IIS worker process (w3wp.exe) hosting your WCF or Web service, captured during the time of slowness. (see steps below on how to capture dumps)
  5. WCF & System.Net tracing (if theย client is not a Web page but an application (Web, desktop or aย service), youย should collect these traces from the client as well.)

FREB

To configure FREB traces, go to IIS Manager, select your Web Site (hosting your WCF Services). On the right hand pane under Actions there is a Configure section; click Failed Request Tracingโ€ฆ

The trace should be enabled. See screen shot below:

snip10

From the center pane, click at Failed Request Tracingโ€ฆ ย as shown below:

snip11

Click Addโ€ฆ as shown below and follow the dialog box.

snip12

If you want to track by time, set it by checking Time taken and click Next. See screen shot below.

snip13

Alternatively (check any one, not both) you canย track by Status code(s), with values 200-999 & click Next to continue. See screen shot below.

snip14

Click at ย Finish as shown in the dialog below. Please note: IIS reset is not required.

snip15

For PerfView & Debug Diagnostic steps see: https://blogs.msdn.microsoft.com/dsnotes/2016/12/30/capturing-full-user-mode-dumps-perfview-traces-for-troubleshooting-high-cpu-hang-issues/

WCF & System.Net tracing

Here is an example of a web.config file with WCF & System.Net tracing enabled. You need to integrate the sections highlighted inย yellow within the correct sections highlighted in cyan.

You can directly use it on your web.config. In initializeData (see below), kindly set the correct path.

<?xml version=โ€1.0โ€ณ encoding=โ€UTF-8โ€ณ?>

<configuration>

ย <system.diagnostics>

ย ย ย  <sources>

ย ย ย ย ย ย  <source name=โ€System.Netโ€ switchValue=โ€Verboseโ€>

ย ย ย ย ย ย ย ย ย ย ย  <listeners>

ย ย ย ย ย ย ย ย ย ย ย ย ย ย  ย <add name=โ€SystemNetTraceโ€/>

ย ย ย ย ย ย ย ย ย ย ย </listeners>

ย ย ย ย ย ย ย </source>

ย ย ย ย ย  <source name=โ€System.ServiceModelโ€ switchValue=โ€Verbose, ActivityTracingโ€ propagateActivity=โ€trueโ€>

ย ย ย ย ย ย ย  <listeners>

ย ย ย ย ย ย ย ย ย  <add name=โ€wcftraceโ€ />

ย ย ย ย ย ย  </listeners>

ย ย ย ย ย  </source>

ย ย ย ย ย  <source name=โ€System.ServiceModel.MessageLoggingโ€ switchValue=โ€Verbose, ActivityTracingโ€>ย ย ย ย ย ย ย 

ย ย ย ย ย ย ย ย <listeners>

ย ย ย ย ย ย ย ย ย  <add name=โ€wcfmessagesโ€ />

ย ย ย ย ย ย ย  </listeners>

ย ย ย ย ย  </source>

ย ย ย ย ย  <source name=โ€System.Runtime.Serializationโ€ switchValue=โ€Verboseโ€>

ย ย ย ย ย ย ย  <listeners>

ย ย ย ย ย ย ย ย ย  <add name=โ€wcfmessagesโ€ />

ย ย ย ย ย ย ย  </listeners>

ย ย ย ย ย  </source>

ย ย  </sources>

ย ย  <sharedListeners>

ย ย 

ย ย ย ย ย ย <add name=โ€SystemNetTraceโ€ type=โ€System.Diagnostics.TextWriterTraceListenerโ€ traceOutputOptions=โ€LogicalOperationStack, DateTime, Timestamp, Callstackโ€ initializeData=โ€C:TracesSystem_Net.txtโ€ />

ย ย 

ย ย ย ย ย ย <add name=โ€wcftraceโ€ type=โ€System.Diagnostics.XmlWriterTraceListenerโ€ traceOutputOptions=โ€LogicalOperationStack, DateTime, Timestamp, Callstackโ€ initializeData=โ€C:TracesWCFTrace.svclogโ€ />

ย 

ย ย ย ย ย  <add name=โ€wcfmessagesโ€ type=โ€System.Diagnostics.XmlWriterTraceListenerโ€ traceOutputOptions=โ€LogicalOperationStack, DateTime, Timestamp, Callstackโ€ initializeData=โ€C:TracesWCFMessages.svclogโ€ />

ย 

ย ย  </sharedListeners>

ย ย  <trace autoflush=โ€trueโ€ />

ย  </system.diagnostics>

ย </configuration>

If you by any chance is working with Microsoft support, send the following for a review or review it yourself to track the origin of slowness.

  1. IIS Logs โ€“ track calls which are taking time. Isolate WCF or Web Service calls taking time.
  2. FREB traces โ€“ Analyze them to see where the calls are stuck for example in the IIS integrated pipeline or somewhere else.
  3. WCF & System.Net traces โ€“ track for errors, exceptions & duration of the calls via the correlation ID.
  4. PerfView traces โ€“ you can track for thread times, ASP.NEt events, etc.
  5. Debug Diagnostic dumps โ€“ track for thread call-stacks, CPU usage, memory usage etc.
โ†ง

์ฃผ๊ฐ„๋‹ท๋„ท 2016๋…„ 12์›” 6์ผ

$
0
0

์—ฌ๋Ÿฌ๋ถ„๋“ค์˜ ์ ๊ทน์ ์ธ ์ฐธ์—ฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜ผ์ž ์•Œ๊ณ  ์žˆ๊ธฐ์—๋Š” ๋„ˆ๋ฌด๋‚˜ ์•„๊นŒ์šด ๊ธ€, ์†Œ์Šค ์ฝ”๋“œ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐœ๊ฒฌํ•˜์…จ๊ฑฐ๋‚˜ ํ˜น์€ ์ง์ ‘ ์ž‘์„ฑํ•˜์…จ๋‹ค๋ฉด Gist๋‚˜ ์ฃผ๊ฐ„๋‹ท๋„ท ํŽ˜์ด์ง€๋ฅผ ํ†ตํ•ด ์•Œ๋ ค์ฃผ์„ธ์š”. .NET ๊ด€๋ จ ๋™ํ˜ธํšŒ ์†Œ์‹๋„ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ์ฃผ๊ฐ„๋‹ท๋„ท์„ ํ†ตํ•ด ๋งŽ์€ ๋ถ„๊ณผ ๊ณต์œ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ธˆ์ฃผ์˜ ์ปค๋ฎค๋‹ˆํ‹ฐ ์†Œ์‹

Taeyo.NET์—์„œ http://docs.asp.net์˜ ASP.NET Core ๋ฌธ์„œ๋ฅผ ํ•œ๊ธ€ํ™”ํ•˜์—ฌ ์—ฐ์žฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

On .NET ์†Œ์‹

์ง€๋‚œ ์ฃผ On .NET์—๋Š” Xavier Decoster๊ฐ€ Maarten Balliauw์™€ ํ•จ๊ป˜ MyGet์— ๊ด€ํ•ด ์ด์•ผ๊ธฐ ๋‚˜๋ˆ„์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ์ฃผ On .NET์—์„œ๋Š” MVP Summit ํ˜„์žฅ์—์„œ MVP๋“ค๊ณผ ํ•จ๊ป˜ ์ธํ„ฐ๋ทฐ๋ฅผ ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • AsyncEx : Stephen Cleary๊ฐ€ async/await๋ฅผ ์œ„ํ•œ ํ—ฌํผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ AsyncEx์— ๊ด€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • IoT, sensors, and Azure : Luis Valencia๊ฐ€ Azure IoT์˜ ์„ผ์„œ ๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ์‹ ํ˜ธ์— ๊ด€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

๊ธˆ์ฃผ์˜ ํŒจํ‚ค์ง€ โ€“ FlexViewer by ComponentOne

.NET ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์ง€์›ํ•˜๋Š” ๋ฆฌํฌํŒ… ํˆด์€ ์ƒ๋‹นํžˆ ๋งŽ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ComponentOne๋Š” ๋ฆฌํฌํŒ… ๊ธฐ๋Šฅ์„ ํฌํ•จํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋งŒ๋“ค๊ณ , ์œ ์ง€๋ณด์ˆ˜ํ•˜๋Š” ์—…์ฒด์ž…๋‹ˆ๋‹ค. FlexViewer๋Š” WinForms, UWP, MVC ํ™˜๊ฒฝ์—์„œ ๋™์ž‘ํ•˜๋ฉฐ PDF, HTML, Office ๋“ฑ ๋‹ค์–‘ํ•œ ํฌ๋งท์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ™ˆํŽ˜์ด์ง€์—์„œย FlexViewer๋ฅผ ์ด์šฉํ•ด 4๋ถ„๋งŒ์— ๋ฆฌํฌํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ธฐ ์˜์ƒ์„ ์ง์ ‘ ํ™•์ธํ•ด ๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

FlexViewer

๊ธˆ์ฃผ์˜ ๊ฒŒ์ž„ โ€“ I Expect You To Die

I Expect You To Die๋Š” VR ํผ์ฆ ๊ฒŒ์ž„์ž…๋‹ˆ๋‹ค. ํ”Œ๋ ˆ์ด์–ด๋Š” ์ตœ๊ณ ์˜ ๋น„๋ฐ€์š”์›์ด ๋˜์–ด ์—ฌ๋Ÿฌ ์œ„ํ—˜ ์ƒํ™ฉ ์†์—์„œ ๋ฏธ์…˜์„ ์™„์ˆ˜ํ•ด์•ผ ํ•˜๋ฉฐ, ๋ฏธ์…˜๋งˆ๋‹ค ์ฃผ์–ด์ง„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ˜„๋ช…ํ•˜๋ฉด์„œ๋„ ๋น ๋ฅธ ์ˆœ๋ฐœ๋ ฅ์„ ์ง€๋…€์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŽธ์•ˆํ•˜๊ฒŒ ์•‰์•„ ํŒ”์„ ๋ป—์€ ์ƒํƒœ๋กœ VR ๊ฒŒ์ž„์„ ์ฆ๊ธฐ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฒŒ์ž„์ƒ์˜ ํผ์ฆ์„ย ํ‘ธ์‹ค ์ˆ˜ ์žˆ์œผ๋ฉฐ,ย ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์‹คํŒจ๋Š” ๋ฏธ์…˜์„ ์™„๋ฃŒํ•˜๋Š” ๋ฐ ๋งŽ์€ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.I Expect You To Die

I Expect You To Die๋Š” Schell Games์—์„œ C#๊ณผ Unity๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ๋˜์—ˆ์œผ๋ฉฐ, ํ˜„์žฌ Oculus Rift์™€ PlayStation VR ๋ฒ„์ „์—์„œ ๊ฒŒ์ž„์„ ์ฆ๊ธฐ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.NET ์†Œ์‹

  • 15 Years of Concurrency : Joe Duffy๊ฐ€ ์ง€๋‚œ Microsoft ์ฐจ์„ธ๋Œ€ ์šด์˜์ฒด์ œ ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ์ธ โ€œ๋ฏธ๋„๋ฆฌโ€œ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์–ป์€ Concurrencyย (๋™์‹œ์„ฑ)์— ๊ด€๋ จํ•œ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Sharing code across .NET platforms with .NET Standard : Jonathan Mezach๊ฐ€ ๊ธฐ์กด์˜ .NET ํ”Œ๋žซํผ๊ณผ .NET Standard ๊ฐ„์— ์ฝ”๋“œ ๊ณต์œ  ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • Evolving the Visual Studio Test Platform โ€“ Part 3: .NET Core, convergence, and cross-plat : Pratap Lakshman๊ฐ€ Evolving the Visual Studio Test Platform์˜ 3๋ฒˆ์งธ ํŒŒํŠธ๋ฅผ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • How I calculate similarities in cookit? : Szymon Warda์ด ์ž์‹ ์ด ๋งŒ๋“  cookit ์‚ฌ์ดํŠธ(์š”๋ฆฌ ๋ ˆ์‹œํ”ผ ๊ด€๋ จ ์ •๋ณด ์ˆ˜์ง‘ ์›น์‚ฌ์ดํŠธ)์—์„œ ์š”๋ฆฌ ์กฐ๋ฆฌ๋ฒ•์˜ ์œ ์‚ฌ์„ฑ์„ ์–ด๋–ป๊ฒŒ ํŒŒ์•…ํ•˜๋Š”์ง€ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Multiple Versions of .NET Core Runtimes and SDK Tools SxS Survive Guide : Nicolรฒ Carandini๊ฐ€ ๋‹ค์ค‘ .NET Core ๋Ÿฐํƒ€์ž„๊ณผ SDK๋ฅผ ์‚ฌ์šฉํ• ๋•Œ, SxS(side by side) ํ™˜๊ฒฝ ๊ตฌ์ถ•์— ํ•„์š”ํ•œ ๊ฐœ๋ฐœ ๊ฐ€์ด๋“œ๋ฅผ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Writing C# build scripts with FAKE, OmniSharp and VS Code : Filip W๊ฐ€ FAKE ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€OmniSharp ๊ทธ๋ฆฌ๊ณ  VS Code๋ฅผ ์ด์šฉํ•œ C# ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ ๋ฐฉ๋ฒ•์— ๊ด€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Implementing the retry pattern for async tasks in C# : Alastair Crabtree๊ฐ€ C# async tasks์˜ retry ํŒจํ„ด ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์— ๊ด€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • 10x speedup utilizing Nagle Algorithm in business application : Ayende Rahien๊ฐ€ ๋„ค์ด๊ธ€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ด์šฉํ•˜์—ฌ 10๋ฐฐ ๋น ๋ฅธ ๋น„์ฆˆ๋‹ˆ์Šค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Designing Akka.NET Applications from Scratch Part 2: Hierarchies and SOLID Principles : Aaron Stannard๊ฐ€ โ€˜Akka.NET์„ ์ด์šฉํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐโ€™ย ๋‘๋ฒˆ์งธ ์Šค๋ฆฌ์ฆˆ์—์„œย Hierarchies ์™€ SOLID Principles์— ๊ด€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • Introduction to Asynchronous Programming in C# (Part 2) (video) : Jeremy Kruer๊ฐ€ C# ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋žจ์— ๊ด€ํ•ด ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.
  • AWS Lambda Supports C# on .NET Coreย : ์ด์ œ .NET Core 1.0 ๋Ÿฐํƒ€์ž„์„ ์‚ฌ์šฉํ•˜์—ฌ C #์—์„œ AWS ๋žŒ๋‹ค ํ•จ์ˆ˜๋ฅผ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Testing Experimental Code in Production with Scientist.NET : Jason Roberts๊ฐ€ Scientist.NET์„ ์ด์šฉํ•˜์—ฌย ๊ฒ€์ฆ๋˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Let .NET framework care about transactions handling for you by implementing IEnlistmentNotification : Mateusz Roszczak์ด .NET framework ํ™˜๊ฒฝ์—์„œ IEnlistmentNotification ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์ถ•ํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • First steps with .NET Core Tools MSBuild โ€œalphaโ€ : Carlos Mendible์ด .NET Core Tools์ธ MSBuild โ€œalphaโ€์˜ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ASP.NET ์†Œ์‹

  • Dockerizing a real world asp.net core application : Thien Nguyen์ด ASP.NET Core ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋„์ปคํ™˜๊ฒฝ์—์„œ ์šด์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Url culture provider using middleware as filters in ASP.NET Core 1.1.0 : Andrew Lock์ด ASP.NET Core 1.1.0์˜ โ€˜๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ•„ํ„ฐ๋กœ ์‚ฌ์šฉํ•˜๊ธฐโ€˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ URL ์„ธ๊ทธ๋จผํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ์š”์ฒญ ์œ„์น˜๋ฅผ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Using Letโ€™s encrypt with ASP.NET Core : Gรฉrald Barrรฉ๊ฐ€ ASP.NET Core์—์„œ ์˜คํ”ˆ ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ โ€œLetโ€™s encryptโ€ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • Bare metal APIs with ASP.NET Core MVC : Ben Foster๊ฐ€ ASP.NET Core MVC๋กœ API๋งŒ ๋นŒ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๊ด€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Updated EF Core & ASP.NET MVC sample to 1.1 : Damien Bod๊ฐ€ Entity Framework Core๋ฅผ ํฌํ•จํ•œ ASP.NET Core 1.1 MVC Sample์„ ์ž์‹ ์˜ Github์— ์—…๋ฐ์ดํŠธํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • Realtime Twitter Stream Visualization with .NET Core, Emitter and JavaScriptย : Roman Atachiants๊ฐ€ โ€˜Emitter messaging brokerโ€™๋ฅผ ์‚ฌ์šฉํ•ด ์‹ค์‹œ๊ฐ„์œผ๋กœ Twitter์— ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์„ ์บก์ฒ˜ํ•˜๊ณ  ๋ธŒ๋กœ๋“œ ์บ์ŠคํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๊ด€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Fat Controller CQRS Diet: Notifications : Derek Comartin์ด CQRS(Command-Query Responsibility Segregation, ๋ช…๋ น๊ณผ ์ฟผ๋ฆฌ์˜ ์—ญํ• ๊ตฌ๋ถ„)๋ฅผ ์ด์šฉํ•˜์—ฌ MVC ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๊ฐœ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ASP.NET: Sharing OWIN Authentication Cookie across IIS Applications : Nandip Makwana๊ฐ€ OWIN ์ธ์ฆ ์ฟ ๊ธฐ๋ฅผ IIS Application์—์„œ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • ASP.NET Core Logging Tutorial : Thomas Ardal์ด ASP.NET Core์—์„œ Logging ํ™œ์šฉ ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ํŠœํ† ๋ฆฌ์–ผ์„ ๊ณต์œ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ASP.NET Core Authentication in a Load Balanced Environment with HAProxy and Redis : Tugberk Ugurlu๊ฐ€ ๋ถ€ํ•˜ ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œย  ASP.NET Core ์ธ์ฆย ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.ย 

F# ์†Œ์‹

  • Azure Notebooks supports F# out of the box!ย : Azure Notebooks์—์„œ F#์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  • F# in Production : Kristian Schmidt๊ฐ€ ์ž์‹ ์˜ ์—…๋ฌด ํ”„๋กœ์ ํŠธ์— F#์„ ํ™œ์šฉํ•œ ๊ฒฝํ—˜๋‹ด์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Introduction to Azure IoT with F# : Chambers๊ฐ€ Azure IoT์—์„œ F# ํ™œ์šฉ ๋ฐฉ๋ฒ•์— ๊ด€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Easy Domain Modeling with Types : Mark Seemann์ด ์—…๋ฌด ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ์‰ฝ๊ฒŒ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” F#์˜ ์žฅ์ ๋“ค์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.
  • Introducing Stream Processing in F# :ย Mikhail Shilkov๊ฐ€ F#์˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๊ธฐ๋Šฅ์ธ Stream Processing์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

Xamarin ์†Œ์‹

Azure ์†Œ์‹

  • Visual Studio Tools for Azure Functions : Andrew B. Hall์ด Visual Studio Tools์—์„œ Azure Function ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.
  • Introducing Microsoft Stream : Scott Hanselman๊ณผ Rob Caron์ด Azure ๊ธฐ๋ฐ˜์˜ ๋น„๋””์˜ค ๊ณต์œ  ํ”Œ๋žซํผ์ธ โ€˜Microsoft Streamโ€™์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.
  • NoSQL .NET Core development using a local Azure DocumentDB Emulatorย : Scott Hanselman์ด Azure DocumentDB Emulator๋ฅผ ์ด์šฉํ•œ .NET Core NoSQL ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • Deploying Azure Functions Automatically : Adrian Hall์ด Azure Functions ์ž๋™ ๋ฐฐํฌ ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Screen Scraping As A Service with Azure Functions in 5 Mins : Jason Roberts๊ฐ€ Azure Functions์„ ์ด์šฉํ•˜์—ฌ 5๋ถ„ ๋งŒ์— Screen Scraping(์ผ์ข…์˜ ์›น ๋ฐ์ดํ„ฐ ํƒ์ƒ‰)๊ธฐ๋Šฅ์„ ์„œ๋น„์Šค๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Games ์†Œ์‹

  • Unity 5.5 Is Ready for Youย : Alex Lian์ด Unity 5.5 ์ถœ์‹œ ์†Œ์‹์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • [Unity 5] Tutorial: How to make a grappling/grapple hook (Video) : Gamad๊ฐ€ grappling/grapple hook ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • Game Design Deep Dive: Controlling two things at once in Soft Body : Zeke Virant๊ฐ€ ๋‘๊ฐœ์˜ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋™์‹œ์— ์ปจํŠธ๋กคํ•ด์•ผ ํ•˜๋Š” ๊ฒŒ์ž„์ธ โ€œSoft Bodyโ€์— ๊ด€ํ•ด ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.
  • Unity3D โ€“ Archery Arrows that Rotate (Video) : Stuart Spence๊ฐ€ ๊ฒŒ์ž„ ์† ํ™”์‚ด์ด ํ˜„์‹ค๊ฐ ์žˆ๊ฒŒ ๋‚ ์•„๊ฐ€๊ฒŒ ๊ตฌํ˜„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Kinematic Equations (E01: introduction) (Video) : Sebastian Lague๊ฐ€ ๊ฒŒ์ž„์—์„œ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์—ญํ•™๊ณต์‹ ์‹œ๋ฆฌ์ฆˆ ์ฒซ๋ฒˆ์งธ ํŽธ์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Unity Tool: Mesh Combine Wizard : Ennoble Studios๊ฐ€ โ€œMesh Combine Wizardโ€ ๋ฌด๋ฃŒ ์œ ๋‹ˆํ‹ฐย ํˆด์„ ์†Œ๊ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฃผ๊ฐ„๋‹ท๋„ท์€ .NET Blog์—์„œ ๋งค์ฃผ ๋ฐœํ–‰ํ•˜๋Š” The week in .NET์„ ๋ฒˆ์—ญํ•˜์—ฌ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ•œ๊ธ€ ๋ฒˆ์—ญ ์ž‘์—…์„ ์˜คํ”ˆ์—์Šค์ง€์˜ ์†ก๊ธฐ์ˆ˜ ์ „๋ฌด๋‹˜์˜ ๋„์›€์„ ๋ฐ›์•„ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

song ์†ก ๊ธฐ์ˆ˜, ๊ธฐ์ˆ  ์ „๋ฌด, ์˜คํ”ˆ์—์Šค์ง€
ํ˜„์žฌ ๊ฐœ๋ฐœ ์ปจ์„คํŒ…ํšŒ์‚ฌ์ธ OpenSG์˜ ๊ธฐ์ˆ ์ด์‚ฌ์ด๋ฉฐ ์—ฌ๋Ÿฌ ์‚ฐ์—…ํ˜„์žฅ์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰์ค‘์ด๋‹ค. ์ž…์‚ฌ ์ „์—๋Š” ๊ต์œก ๊ฐ•์‚ฌ๋กœ์„œ ์‚ผ์„ฑ ๋ฉ€ํ‹ฐ์บ ํผ์Šค ๊ต์œก์„ผํ„ฐ ๋“ฑ์—์„œ ๊ฐœ๋ฐœ์ž .NET ๊ณผ์ •์„ ์ง„ํ–‰ํ•ด ์™”์œผ๋ฉฐ 2005๋…„๋ถ€ํ„ฐ TechED Korea, DevDays, MSDN Seminar๋“ฑ ๊ฐœ๋ฐœ์ž ์ปจํผ๋Ÿฐ์Šค์˜ ์Šคํ”ผ์ปค๋กœ๋„ ํ™œ๋™ํ•˜๊ณ ์žˆ๋‹ค. ์ตœ๊ทผ์—๋Š” ํ•˜๋ฃจ ์—…๋ฌด์˜ ๋Œ€๋‹ค์ˆ˜ ์‹œ๊ฐ„์„ ๋น„์ฃผ์–ผ ์ŠคํŠœ๋””์˜ค์™€ ๊ฐ™์ด ๋ณด๋‚ด๋ฉฐ ์ผ ๋…„์— ํ•œ ๊ถŒ ์ •๋„ ์ฑ…์„ ์“ฐ๊ณ , ํ•œ๋‹ฌ์— ๋‘ ๋ฒˆ ์ •๋„ ๊ฐ•์˜๋ฅผ ํ•˜๋ฉด ํ–‰๋ณตํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ฏฟ๋Š” โ€˜Happy Developerโ€™ ์ด๋‹ค.

ย 

โ†ง

Happy New Year Friday Five

$
0
0

gus-gonzalesVideo:ย Top 5 countdown of tips for New Microsoft Dynamics 365 Administrators

Gus Gonzalez is a 5-time Microsoft MVP, and leads the vision, growth, and strategic direction at Elev8 Solutions. He has 15 years of consulting experience in the IT Industry, in which heโ€™s designed and implemented Microsoft Solutions. He has worked in the Microsoft Dynamics 365/CRM industry since 2006. He began his CRM Career as a System Administrator and over time, moved up to Global Technical lead, Functional Consultant, and Solution Architect. A CRMUG All Star, Granite Award Winner, world-class trainer and readiness expert, Gus has a passion for creating solutions that organizations can count on, and users love working with. Follow him on Twitterย @GusGonzalez2.

ย 

freek-berson-1Azure Resource Manager and JSON templates to deploy RDS in Azure IaaS

Freek Bersonย is an Infrastructure specialist at Wortell, a system integrator company based in the Netherlands. Here he focuses on End User Computing and related technologies, mostly on the Microsoft platform. He is also a managing consultant at rdsgurus.com. He maintains his personal blog at themicrosoftplatform.net where he writes articles related to Remote Desktop Services, Azure and other Microsoft technologies. An MVP since 2011, Freek is also an active moderator on TechNet Forum and contributor to Microsoft TechNet Wiki. He speaks at conferences including BriForum, E2EVC and ExpertsLive. Join his RDS Group on Linked-In here.ย Follow him on Twitterย @fberson.

ย 

herve-roggero

Exploring Microsoft Azure DocumentDB

Herve Roggero is a Microsoft Azure MVP and the founder of Enzo Unified.ย Herveโ€™s experience includes software development, architecture, database administration and senior management with both global corporations and startup companies. Herve also runs the Azure Florida Association. Follow him on Twitterย @hroggero.

ย 

ย 

ย 

ย 

oscar-garciaApp Service Authentication with Azure AD

Oscar Garcia is a Software Solutions Architect who resides in Sunny South Florida. He is a Microsoft MVP and certified solutions developer with many years of experience building solutions using .Net framework and multiple open source frameworks. Currently, he specializes in building cloud solutions using technologies likeย ASP.NET, NodeJS, AngularJS, and other JavaScript frameworks. You can follow Oscar on Twitter via @ozkary or by visiting his blog atย ozkary.com.

ย 

ย 

jay-r-barrios

Upgrade Active Directory Server 2016 from Server 2012ย R2

Jay-R Barrios is a Filipino IT Seniorย Consultant based in Singapore. He helpsย his clients in designing and deploying their Microsoft Active Directory and System Centerย Infrastructure. In 2005, he and other IT Professionals from msforums ph founded the Philippine Windows Users Group PHIWUG. He served 2 terms as its President from 2008 and 2009 and is currently managing the System Center Philippines user group. If not geeking around, Jay-R likes to Travel,ย Surf and regularly plays soccer with his friends (on theย field or in video games). Follow him on Twitterย @jayrbarrios.
โ†ง
Viewing all 12366 articles
Browse latest View live