Merge pull request #19569 from jtattermusch/csharp_internal_span_use

C#: add System.Memory dependency and use Span<> internally for all target frameworks 
diff --git a/src/csharp/Grpc.Core.Api/DeserializationContext.cs b/src/csharp/Grpc.Core.Api/DeserializationContext.cs
index 966bcfa..b0c3bad 100644
--- a/src/csharp/Grpc.Core.Api/DeserializationContext.cs
+++ b/src/csharp/Grpc.Core.Api/DeserializationContext.cs
@@ -48,13 +48,12 @@
             throw new NotImplementedException();
         }
 
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
         /// <summary>
         /// Gets the entire payload as a ReadOnlySequence.
         /// The ReadOnlySequence is only valid for the duration of the deserializer routine and the caller must not access it after the deserializer returns.
         /// Using the read only sequence is the most efficient way to access the message payload. Where possible it allows directly
         /// accessing the received payload without needing to perform any buffer copying or buffer allocations.
-        /// NOTE: This method is only available in the netstandard2.0 build of the library.
+        /// NOTE: When using this method, it is recommended to use C# 7.2 compiler to make it more useful (using Span type directly from your code requires C# 7.2)."
         /// NOTE: Deserializers are expected not to call this method (or other payload accessor methods) more than once per received message
         /// (as there is no practical reason for doing so) and <c>DeserializationContext</c> implementations are free to assume so.
         /// </summary>
@@ -63,6 +62,5 @@
         {
             throw new NotImplementedException();
         }
-#endif        
     }
 }
diff --git a/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj b/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj
index 0a95829..a0d41a2 100755
--- a/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj
+++ b/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj
@@ -20,18 +20,11 @@
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
 
-  <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
-    <DefineConstants>$(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY</DefineConstants>
-  </PropertyGroup>
-
   <Import Project="..\Grpc.Core\SourceLink.csproj.include" />
 
   <ItemGroup>
     <PackageReference Include="System.Interactive.Async" Version="3.2.0" />
-  </ItemGroup>
-
-  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
-    <PackageReference Include="System.Memory" Version="4.5.2" />
+    <PackageReference Include="System.Memory" Version="4.5.3" />
   </ItemGroup>
 
   <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 693646b..1aa314f 100755
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -9,10 +9,6 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
 
-  <PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
-    <DefineConstants>$(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY</DefineConstants>
-  </PropertyGroup>
-
   <ItemGroup>
     <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs b/src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs
index 63baab3..8b635f9 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs
@@ -17,18 +17,14 @@
 #endregion
 
 using System;
+using System.Buffers;
 using System.Collections.Generic;
+using System.Runtime.InteropServices;
 using Grpc.Core;
 using Grpc.Core.Internal;
 using Grpc.Core.Utils;
 using NUnit.Framework;
 
-using System.Runtime.InteropServices;
-
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
-using System.Buffers;
-#endif
-
 namespace Grpc.Core.Internal.Tests
 {
     public class DefaultDeserializationContextTest
@@ -47,7 +43,6 @@
             fakeBufferReaderManager.Dispose();
         }
 
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
         [TestCase]
         public void PayloadAsReadOnlySequence_ZeroSegmentPayload()
         {
@@ -118,7 +113,6 @@
 
             Assert.IsFalse(segmentEnumerator.MoveNext());
         }
-#endif
 
         [TestCase]
         public void NullPayloadNotAllowed()
@@ -196,9 +190,7 @@
 
             // Getting payload multiple times is illegal
             Assert.Throws(typeof(InvalidOperationException), () => context.PayloadAsNewBuffer());
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
             Assert.Throws(typeof(InvalidOperationException), () => context.PayloadAsReadOnlySequence());
-#endif
         }
 
         [TestCase]
@@ -215,9 +207,7 @@
 
             Assert.AreEqual(0, context.PayloadLength);
             Assert.Throws(typeof(NullReferenceException), () => context.PayloadAsNewBuffer());
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
             Assert.Throws(typeof(NullReferenceException), () => context.PayloadAsReadOnlySequence());
-#endif
 
             // Previously reset context can be initialized again
             var origBuffer2 = GetTestBuffer(50);
diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs
index 7c4ff65..8211b7f 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs
@@ -103,7 +103,7 @@
         private void AssertSliceDataEqual(byte[] expected, Slice actual)
         {
             var actualSliceData = new byte[actual.Length];
-            actual.CopyTo(new ArraySegment<byte>(actualSliceData));
+            actual.ToSpanUnsafe().CopyTo(actualSliceData);
             CollectionAssert.AreEqual(expected, actualSliceData);
         }
 
diff --git a/src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs b/src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs
index 7630785..bfe4f64 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs
@@ -17,19 +17,15 @@
 #endregion
 
 using System;
+using System.Buffers;
 using System.Collections.Generic;
 using System.Linq;
+using System.Runtime.InteropServices;
 using Grpc.Core;
 using Grpc.Core.Internal;
 using Grpc.Core.Utils;
 using NUnit.Framework;
 
-using System.Runtime.InteropServices;
-
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
-using System.Buffers;
-#endif
-
 namespace Grpc.Core.Internal.Tests
 {
     // Converts IBufferReader into instances of ReadOnlySequence<byte>
@@ -50,7 +46,6 @@
             fakeBufferReaderManager.Dispose();
         }
 
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
         [TestCase]
         public void NullPayload()
         {
@@ -131,13 +126,7 @@
             }
             return result;
         }
-#else
-        [TestCase]
-        public void OnlySupportedOnNetCore()
-        {
-            // Test case needs to exist to make C# sanity test happy.
-        }
-#endif
+
         private byte[] GetTestBuffer(int length)
         {
             var testBuffer = new byte[length];
diff --git a/src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs b/src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs
index eb090bb..ff4d747 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs
@@ -33,7 +33,7 @@
         [TestCase(10)]
         [TestCase(100)]
         [TestCase(1000)]
-        public void SliceFromNativePtr_CopyToArraySegment(int bufferLength)
+        public void SliceFromNativePtr_Copy(int bufferLength)
         {
             var origBuffer = GetTestBuffer(bufferLength);
             var gcHandle = GCHandle.Alloc(origBuffer, GCHandleType.Pinned);
@@ -43,7 +43,7 @@
                 Assert.AreEqual(bufferLength, slice.Length);
 
                 var newBuffer = new byte[bufferLength];
-                slice.CopyTo(new ArraySegment<byte>(newBuffer));
+                slice.ToSpanUnsafe().CopyTo(newBuffer);
                 CollectionAssert.AreEqual(origBuffer, newBuffer);
             }
             finally
@@ -52,23 +52,6 @@
             }
         }
 
-        [TestCase]
-        public void SliceFromNativePtr_CopyToArraySegmentTooSmall()
-        {
-            var origBuffer = GetTestBuffer(100);
-            var gcHandle = GCHandle.Alloc(origBuffer, GCHandleType.Pinned);
-            try
-            {
-                var slice = new Slice(gcHandle.AddrOfPinnedObject(), origBuffer.Length);
-                var tooSmall = new byte[origBuffer.Length - 1];
-                Assert.Catch(typeof(ArgumentException), () => slice.CopyTo(new ArraySegment<byte>(tooSmall)));
-            }
-            finally
-            {
-                gcHandle.Free();
-            }
-        }
-
         // create a buffer of given size and fill it with some data
         private byte[] GetTestBuffer(int length)
         {
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 1844ce3..b7c7851 100755
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -23,9 +23,8 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
 
-  <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
+  <PropertyGroup>
     <LangVersion>7.2</LangVersion>
-    <DefineConstants>$(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY</DefineConstants>
   </PropertyGroup>
 
   <ItemGroup>
@@ -100,8 +99,7 @@
 
   <ItemGroup>
     <PackageReference Include="System.Interactive.Async" Version="3.2.0" />
-    <!-- System.Buffers *may* come in transitively, but: we can *always* use ArrayPool -->
-    <PackageReference Include="System.Buffers" Version="4.5.0" />
+    <PackageReference Include="System.Memory" Version="4.5.3" />
   </ItemGroup>
 
   <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
diff --git a/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs b/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs
index 946c37d..7b5997b 100644
--- a/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs
+++ b/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs
@@ -16,13 +16,10 @@
 
 #endregion
 
-using Grpc.Core.Utils;
 using System;
-using System.Threading;
-
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
 using System.Buffers;
-#endif
+using System.Threading;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
 {
@@ -33,9 +30,7 @@
 
         IBufferReader bufferReader;
         int payloadLength;
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
         ReusableSliceBuffer cachedSliceBuffer = new ReusableSliceBuffer();
-#endif
 
         public DefaultDeserializationContext()
         {
@@ -47,18 +42,16 @@
         public override byte[] PayloadAsNewBuffer()
         {
             var buffer = new byte[payloadLength];
-            FillContinguousBuffer(bufferReader, buffer);
+            PayloadAsReadOnlySequence().CopyTo(buffer);
             return buffer;
         }
 
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
         public override ReadOnlySequence<byte> PayloadAsReadOnlySequence()
         {
             var sequence = cachedSliceBuffer.PopulateFrom(bufferReader);
             GrpcPreconditions.CheckState(sequence.Length == payloadLength);
             return sequence;
         }
-#endif
 
         public void Initialize(IBufferReader bufferReader)
         {
@@ -70,9 +63,7 @@
         {
             this.bufferReader = null;
             this.payloadLength = 0;
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
             this.cachedSliceBuffer.Invalidate();
-#endif
         }
 
         public static DefaultDeserializationContext GetInitializedThreadLocal(IBufferReader bufferReader)
@@ -81,21 +72,5 @@
             instance.Initialize(bufferReader);
             return instance;
         }
-
-        private void FillContinguousBuffer(IBufferReader reader, byte[] destination)
-        {
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
-            PayloadAsReadOnlySequence().CopyTo(new Span<byte>(destination));
-#else
-            int offset = 0;
-            while (reader.TryGetNextSlice(out Slice slice))
-            {
-                slice.CopyTo(new ArraySegment<byte>(destination, offset, (int)slice.Length));
-                offset += (int)slice.Length;
-            }
-            // check that we filled the entire destination
-            GrpcPreconditions.CheckState(offset == payloadLength);
-#endif
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs b/src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs
index 2d38509..078e59e 100644
--- a/src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs
+++ b/src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs
@@ -16,8 +16,6 @@
 
 #endregion
 
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
-
 using Grpc.Core.Utils;
 using System;
 using System.Threading;
@@ -145,4 +143,3 @@
         }
     }
 }
-#endif
diff --git a/src/csharp/Grpc.Core/Internal/Slice.cs b/src/csharp/Grpc.Core/Internal/Slice.cs
index 22eb953..b6e0701 100644
--- a/src/csharp/Grpc.Core/Internal/Slice.cs
+++ b/src/csharp/Grpc.Core/Internal/Slice.cs
@@ -40,14 +40,6 @@
 
         public int Length => length;
 
-        // copies data of the slice to given span.
-        // there needs to be enough space in the destination buffer
-        public void CopyTo(ArraySegment<byte> destination)
-        {
-            Marshal.Copy(dataPtr, destination.Array, destination.Offset, length);
-        }
-
-#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
         public Span<byte> ToSpanUnsafe()
         {
             unsafe
@@ -55,7 +47,6 @@
                 return new Span<byte>((byte*) dataPtr, length);
             }
         }
-#endif
 
         /// <summary>
         /// Returns a <see cref="System.String"/> that represents the current <see cref="Grpc.Core.Internal.Slice"/>.
diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat
index 4211d70..06552e8 100644
--- a/src/csharp/build_unitypackage.bat
+++ b/src/csharp/build_unitypackage.bat
@@ -65,6 +65,9 @@
 @rem add gRPC dependencies
 @rem TODO(jtattermusch): also include XMLdoc
 copy /Y Grpc.Core\bin\Release\net45\System.Interactive.Async.dll unitypackage\unitypackage_skeleton\Plugins\System.Interactive.Async\lib\net45\System.Interactive.Async.dll || goto :error
+copy /Y Grpc.Core\bin\Release\net45\System.Runtime.CompilerServices.Unsafe.dll unitypackage\unitypackage_skeleton\Plugins\System.Runtime.CompilerServices.Unsafe\lib\net45\System.Runtime.CompilerServices.Unsafe.dll || goto :error
+copy /Y Grpc.Core\bin\Release\net45\System.Buffers.dll unitypackage\unitypackage_skeleton\Plugins\System.Buffers\lib\net45\System.Buffers.dll || goto :error
+copy /Y Grpc.Core\bin\Release\net45\System.Memory.dll unitypackage\unitypackage_skeleton\Plugins\System.Memory\lib\net45\System.Memory.dll || goto :error
 
 @rem add Google.Protobuf
 @rem TODO(jtattermusch): also include XMLdoc
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib.meta
new file mode 100644
index 0000000..754fcae
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 0cb4be3dca2a49e6a920da037ea13d80
+folderAsset: yes
+timeCreated: 1531219385
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45.meta
new file mode 100644
index 0000000..00368db
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 53b3f7a608814da5a3e3207d10c85b4e
+folderAsset: yes
+timeCreated: 1531219385
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45/System.Buffers.dll.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45/System.Buffers.dll.meta
new file mode 100644
index 0000000..6a9eae1
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45/System.Buffers.dll.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: bb037a236f584460af82c59c5d5ad972
+timeCreated: 1531219386
+licenseType: Free
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  isPreloaded: 0
+  isOverridable: 0
+  platformData:
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  - first:
+      Windows Store Apps: WindowsStoreApps
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45/System.Buffers.xml.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45/System.Buffers.xml.meta
new file mode 100644
index 0000000..14b3b36
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Buffers/lib/net45/System.Buffers.xml.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 4b9fff86d3b2471eb0003735b3ce3a51
+timeCreated: 1531219386
+licenseType: Free
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib.meta
new file mode 100644
index 0000000..eab9851
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 3d6c20bf92b74c03b1ba691cbce610e4
+folderAsset: yes
+timeCreated: 1531219385
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45.meta
new file mode 100644
index 0000000..2d33fd9
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 7164a0a387b24d1a9d76f6d558fc44d2
+folderAsset: yes
+timeCreated: 1531219385
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45/System.Memory.dll.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45/System.Memory.dll.meta
new file mode 100644
index 0000000..11af5ea
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45/System.Memory.dll.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: e774d51b8ba64a988dd37135e487105c
+timeCreated: 1531219386
+licenseType: Free
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  isPreloaded: 0
+  isOverridable: 0
+  platformData:
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  - first:
+      Windows Store Apps: WindowsStoreApps
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45/System.Memory.xml.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45/System.Memory.xml.meta
new file mode 100644
index 0000000..4c04ced
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Memory/lib/net45/System.Memory.xml.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 3d27c5afe3114f67b0f6e27e36b89d5c
+timeCreated: 1531219386
+licenseType: Free
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib.meta
new file mode 100644
index 0000000..b3a382a
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: f51cc0f065424fb2928eee7c2804bfd8
+folderAsset: yes
+timeCreated: 1531219385
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45.meta
new file mode 100644
index 0000000..4154241
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: aad21c5c1f2f4c1391b1e4a475f163bb
+folderAsset: yes
+timeCreated: 1531219385
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45/System.Runtime.CompilerServices.Unsafe.dll.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45/System.Runtime.CompilerServices.Unsafe.dll.meta
new file mode 100644
index 0000000..c3988ca
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45/System.Runtime.CompilerServices.Unsafe.dll.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: d378b9cd266a4a448f071c114e5f18cb
+timeCreated: 1531219386
+licenseType: Free
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  isPreloaded: 0
+  isOverridable: 0
+  platformData:
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  - first:
+      Windows Store Apps: WindowsStoreApps
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45/System.Runtime.CompilerServices.Unsafe.xml.meta b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45/System.Runtime.CompilerServices.Unsafe.xml.meta
new file mode 100644
index 0000000..e756ced
--- /dev/null
+++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/System.Runtime.CompilerServices.Unsafe/lib/net45/System.Runtime.CompilerServices.Unsafe.xml.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: cfa8e546fee54a5ea3b20cf9dcf90fdf
+timeCreated: 1531219386
+licenseType: Free
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/templates/src/csharp/build_unitypackage.bat.template b/templates/src/csharp/build_unitypackage.bat.template
index d6f2e3c..07f19c2 100755
--- a/templates/src/csharp/build_unitypackage.bat.template
+++ b/templates/src/csharp/build_unitypackage.bat.template
@@ -67,6 +67,9 @@
   @rem add gRPC dependencies
   @rem TODO(jtattermusch): also include XMLdoc
   copy /Y Grpc.Core\bin\Release\net45\System.Interactive.Async.dll unitypackage\unitypackage_skeleton\Plugins\System.Interactive.Async\lib\net45\System.Interactive.Async.dll || goto :error
+  copy /Y Grpc.Core\bin\Release\net45\System.Runtime.CompilerServices.Unsafe.dll unitypackage\unitypackage_skeleton\Plugins\System.Runtime.CompilerServices.Unsafe\lib\net45\System.Runtime.CompilerServices.Unsafe.dll || goto :error
+  copy /Y Grpc.Core\bin\Release\net45\System.Buffers.dll unitypackage\unitypackage_skeleton\Plugins\System.Buffers\lib\net45\System.Buffers.dll || goto :error
+  copy /Y Grpc.Core\bin\Release\net45\System.Memory.dll unitypackage\unitypackage_skeleton\Plugins\System.Memory\lib\net45\System.Memory.dll || goto :error
 
   @rem add Google.Protobuf
   @rem TODO(jtattermusch): also include XMLdoc