{"id":3338,"date":"2020-09-10T14:23:16","date_gmt":"2020-09-10T12:23:16","guid":{"rendered":"http:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/?p=3338"},"modified":"2020-09-10T16:24:11","modified_gmt":"2020-09-10T14:24:11","slug":"sharepoint-csom-ya-disponible-en-net-standard","status":"publish","type":"post","link":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/sharepoint-csom-ya-disponible-en-net-standard\/","title":{"rendered":"SharePoint CSOM ya disponible en .NET Standard"},"content":{"rendered":"<div class=\"post-date\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3339 size-full\" title=\"SharePoint CSOM ya disponible en .NET Standard \" src=\"http:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg\" alt=\"SharePoint CSOM ya disponible en .NET Standard \" width=\"1115\" height=\"801\" srcset=\"https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg 1115w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri-300x216.jpg 300w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri-1024x736.jpg 1024w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri-768x552.jpg 768w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri-610x438.jpg 610w\" sizes=\"auto, (max-width: 1115px) 100vw, 1115px\" \/><\/div>\n<p>A finales de junio, se public\u00f3 una versi\u00f3n estable y oficial de uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: <strong>CSOM para .NET Standard<\/strong>, o lo que es lo mismo, la librer\u00eda Cliente para poder acceder a SharePoint. En este art\u00edculo vamos a explicar los motivos de esta demanda y veremos tambi\u00e9n c\u00f3mo empezar a usarlo con un sencillo ejemplo \ud83d\ude42<\/p>\n<p><!--more--><\/p>\n<h1 id=\"historia\">Historia<\/h1>\n<p>En estos momentos, hablar de la importancia que tiene que una librer\u00eda en una determinada tecnolog\u00eda, visto desde la perspectiva de cualquier tecn\u00f3logo, puede parecer un sinsentido si no se tiene el contexto, \u00bfy cu\u00e1l es el contexto? La forma en la que desarrolla en los productos Microsoft ha evolucionado mucho en los \u00faltimos a\u00f1os.<\/p>\n<p>Microsoft dispone de muchos productos que se utilizan en much\u00edsimos clientes como son SharePoint, Dynamics CRM, \u2026 Estos productos, hace no muchos a\u00f1os, se instalaban en la infraestructura de los clientes y el desarrollo se realizaba instalando \u201cartefactos\u201d en dicho servidor. Ahora bien, los tiempos cambian y estos productos ahora son servicios que consumimos en el Cloud, y naturalmente no tenemos acceso al servidor para instalar nada.<\/p>\n<p>Esto implic\u00f3 un gran cambio en la forma de desarrollar sobre SharePoint. Pasamos de un desarrollo en <strong>lenguajes de servidor como C#<\/strong> a especialistas en el <strong>FrontEnd<\/strong>. La cuesti\u00f3n no es solo un cambio de tecnolog\u00eda (cambiar C# por Typescript con el frameworks que m\u00e1s rabia nos d\u00e9), sino que muchas de las acciones que se hac\u00edan en los desarrollos, ahora no se pueden hacer.<\/p>\n<p>Acciones como poder <em>impersonar<\/em> usuarios al estar en el Front. No se pueden hacer procesos \u201cprogramados\u201d\/\u201cbajo demanda\u201d para integraci\u00f3n con otros sistemas (y aunque se pudiera, no ser\u00eda una opci\u00f3n a plantear). Para poder hacer esta funcionalidad ten\u00edamos\u00a0 que utilizar CSOM( Client SharePoint Object Model) o bien directamente llamadas a la API Rest de SharePoint. La problem\u00e1tica en este punto, es que la <strong>API Rest de SharePoint<\/strong> no tiene todos los endpoint ni toda la funcionalidad que hay en CSOM y adem\u00e1s, CSOM es mucho m\u00e1s f\u00e1cil de utilizar. En este punto, CSOM fue relativamente importante, tanto para a\u00f1adirlo en API Rest Custom como en el uso de Azure Functions. En las primeras versiones, cuando Azure Functions en su versi\u00f3n 1.0 era .NET Framework y .NET Core estaba en sus primeras versiones (con todas las dudas sobre su evoluci\u00f3n y el camino que iba a seguir), un desarrollador de Office pod\u00eda extender su desarrollo de una forma natural. Conforme aumentaron las versiones de dichos productos y su implantaci\u00f3n fue mayor,\u00a0 poder usar una Azure Function en el contexto de SharePoint se convirti\u00f3 en algo relativamente complejo. Muchos en este punto pensar\u00e9is qu\u00e9 necesidades puede tener\u00a0 hacer uso de SharePoint en una Azure Functions. Imaginad que tengo unos documentos en SharePoint y quiero mandarlos a un almacenamiento m\u00e1s ligero para tenerlo en un hist\u00f3rio como Blob Storage. Para hacer este desarrollo, anta\u00f1o ten\u00edamos dos opciones:<\/p>\n<ul>\n<li>Hacer uso de Azure Functions en versi\u00f3n 1.0 (con sus contras: obsoleto, tuning del toolings de herramientas)<\/li>\n<li>Hacer uso de Azure Functions en versi\u00f3n 2.0 o superior (tened en cuenta que la comunicaci\u00f3n con todo lo relacionado con SharePoint se tendr\u00eda que poner una \u201cpieza\u201d(API Rest) implementada en .NET Framework).<\/li>\n<\/ul>\n<p>Como pod\u00e9is ver, cualquiera de estas opciones no es la mejor. Independientemente de la que escojamos, siempre elegimos la menos mala. Ahora bien, con la llegada de CSOM en .NET Standard todos estos impedimentos desaparecen. Ahora tenemos otras cosas, y las primeras preguntas que surgen son \u00bfCSOM en .NET Framework y Standard tienen las mismas opciones? \u00bfSon iguales?<\/p>\n<h1 id=\"qu\u00e9-cosas-podemos-hacer-con-csom-en-net-core-o-m\u00e1s-bien-cu\u00e1les-son-sus-limitaciones\">\u00bfQu\u00e9 cosas podemos hacer con CSOM en .NET Core y cu\u00e1les son sus limitaciones?<\/h1>\n<p>Lo primero que indica la documentaci\u00f3n es que esta versi\u00f3n de CSOM solo es compatible con la versi\u00f3n Online de SharePoint. En las versiones OnPremise no est\u00e1 actualizada ni soportada.<\/p>\n<p>El principal cambio del uso de esta librer\u00eda es que no soporta ning\u00fan m\u00e9todo que tenga la autenticaci\u00f3n SharePointOnlineCredentials, el uso de la autenticaci\u00f3n basada en usuario\/contrase\u00f1a es un m\u00e9todo com\u00fan para los programadores que usan CSOM para .NET Framework. En CSOM para .NET Standard esto ya no es posible. Es el desarrollador que usa CSOM para .NET Standard para obtener un token de acceso de OAuth y usarlo para realizar llamadas a SharePoint Online.<\/p>\n<p>El m\u00e9todo recomendado para obtener tokens de acceso para SharePoint Online es <strong>configurar una aplicaci\u00f3n de Azure AD<\/strong>. Para CSOM para .NET Standard lo \u00fanico que importa es que se obtenga un <strong>token de acceso v\u00e1lido<\/strong>, ya que puede usar el flujo de credenciales de la contrase\u00f1a del propietario del recurso mediante el inicio de sesi\u00f3n de dispositivo y la autenticaci\u00f3n basada en certificados,<\/p>\n<p>En el tema de m\u00e9todos de CSOM no se han reescrito:<\/p>\n<ul>\n<li>SaveBinaryDirect \/ OpenBinaryDirectAPI (basada en WebDAV)=&gt; El motivo es claro. Para poder llegar al fichero es necesario tener una autenticaci\u00f3n que hoy en d\u00eda no est\u00e1 permitida. El uso de estos m\u00e9todos se hacen dependiendo del tama\u00f1o de ficheros que queremos realizar (esto dar\u00eda para un art\u00edculo solamente).<\/li>\n<li>Microsoft.SharePoint.Client.Utilities.HttpUtility =&gt; Todos estos m\u00e9todos que se utilizaban est\u00e1n escritos en el propio Framework con lo cual han hecho caso al no tener dos librer\u00edas que hacen lo mismo<\/li>\n<li>EventReceiver =&gt; Aunque parezca mentira, a\u00fan estaban este tipo de Artefactos soportados en el Frameworks (a pesar de que todo el mundo ya usaba como desencadenadores otros artefactos de Azure como las mencionadas Azure Functions, Logic Apps,etc)<\/li>\n<\/ul>\n<h1 id=\"veamos-un-ejemplo\">Veamos un ejemplo<\/h1>\n<h2 id=\"crear-la-aplicaci\u00f3n-en-el-azure-active-directory\">Crear la aplicaci\u00f3n en el Azure Active Directory<\/h2>\n<ul>\n<li>Ir a Azure AD portal a trav\u00e9s de\u00a0<a href=\"https:\/\/aad.portal.azure.com\/\">https:\/\/aad.portal.azure.com<\/a><\/li>\n<li>Haz clic en Azure Active Directory y en los registros de aplicaciones en el panel de navegaci\u00f3n izquierdo<\/li>\n<li>Haz clic en nuevo registro<img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/csom-net-core\/registrarApp.PNG\" alt=\"nuevo registro\" width=\"2104\" height=\"1726\" \/><\/li>\n<li>Escribe un nombre para la aplicaci\u00f3n y haz clic en registrar.<\/li>\n<li>Ves a permisos de la API para conceder permisos a la aplicaci\u00f3n, haz clic en Agregar permiso, elige SharePoint, permisos delegados y selecciona por ejemplo AllSites. administrar. Haz clic en conceder consentimiento de administrador para aceptar los permisos solicitados de la aplicaci\u00f3n.<img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/csom-net-core\/solicitudPermisos.PNG\" alt=\"dar permisos SharePoint\" width=\"1611\" height=\"1686\" \/><\/li>\n<li>Haz clic en autenticaci\u00f3n en el panel de navegaci\u00f3n izquierdo<\/li>\n<li>Cambia tipo de cliente predeterminado-tratar aplicaci\u00f3n como cliente p\u00fablico de no a s\u00ed<\/li>\n<li>Haz clic en informaci\u00f3n general y copia el identificador de la aplicaci\u00f3n en el portapapeles (lo necesitaremos m\u00e1s adelante).<\/li>\n<\/ul>\n<h2 id=\"crear-la-aplicaci\u00f3n-de-consola\">Crear la Aplicaci\u00f3n de Consola<\/h2>\n<ul>\n<li>Crearemos una aplicaci\u00f3n de consola. Bien usando la l\u00ednea de comando o bien directamente desde Visual Studio<\/li>\n<\/ul>\n<div class=\"highlight\">\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\ndotnet new console\r\n<\/pre>\n<\/div>\n<ul>\n<li>A\u00f1adiremos los siguientes paquetes de nuget . Microsoft.SharePointOnline.CSOM . System.IdentityModel.Token.Jwt<\/li>\n<li>Nos creamos una clase autenticacion manager<\/li>\n<\/ul>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing Microsoft.SharePoint.Client;\r\nusing System;\r\nusing System.Collections.Concurrent;\r\nusing System.Net.Http;\r\nusing System.Security;\r\nusing System.Text;\r\nusing System.Text.Json;\r\nusing System.Threading;\r\nusing System.Threading.Tasks;\r\nusing System.Web;\r\n\r\nnamespace Example_CSOM_NET_Standar\r\n{\r\n    public class AuthenticationManager : IDisposable\r\n    {\r\n        private static readonly HttpClient httpClient = new HttpClient();\r\n        private const string tokenEndpoint = &quot;https:\/\/login.microsoftonline.com\/common\/oauth2\/token&quot;;\r\n\r\n        private const string defaultAADAppId = &quot;clientid&quot;;\r\n\r\n        \/\/ Token cache handling\r\n        private static readonly SemaphoreSlim semaphoreSlimTokens = new SemaphoreSlim(1);\r\n        private AutoResetEvent tokenResetEvent = null;\r\n        private readonly ConcurrentDictionary&amp;lt;string, string&amp;gt; tokenCache = new ConcurrentDictionary&amp;lt;string, string&amp;gt;();\r\n        private bool disposedValue;\r\n\r\n        internal class TokenWaitInfo\r\n        {\r\n            public RegisteredWaitHandle Handle = null;\r\n        }\r\n\r\n        public ClientContext GetContext(Uri web, string userPrincipalName, SecureString userPassword)\r\n        {\r\n            var context = new ClientContext(web);\r\n\r\n            context.ExecutingWebRequest += (sender, e) =&amp;gt;\r\n            {\r\n                string accessToken = EnsureAccessTokenAsync(new Uri($&quot;{web.Scheme}:\/\/{web.DnsSafeHost}&quot;), userPrincipalName, new System.Net.NetworkCredential(string.Empty, userPassword).Password).GetAwaiter().GetResult();\r\n                e.WebRequestExecutor.RequestHeaders&#x5B;&quot;Authorization&quot;] = &quot;Bearer &quot; + accessToken;\r\n            };\r\n\r\n            return context;\r\n        }\r\n\r\n\r\n        public async Task&amp;lt;string&amp;gt; EnsureAccessTokenAsync(Uri resourceUri, string userPrincipalName, string userPassword)\r\n        {\r\n            string accessTokenFromCache = TokenFromCache(resourceUri, tokenCache);\r\n            if (accessTokenFromCache == null)\r\n            {\r\n                await semaphoreSlimTokens.WaitAsync().ConfigureAwait(false);\r\n                try\r\n                {\r\n                    \/\/ No async methods are allowed in a lock section\r\n                    string accessToken = await AcquireTokenAsync(resourceUri, userPrincipalName, userPassword).ConfigureAwait(false);\r\n                    Console.WriteLine($&quot;Successfully requested new access token resource {resourceUri.DnsSafeHost} for user {userPrincipalName}&quot;);\r\n                    AddTokenToCache(resourceUri, tokenCache, accessToken);\r\n\r\n                    \/\/ Register a thread to invalidate the access token once's it's expired\r\n                    tokenResetEvent = new AutoResetEvent(false);\r\n                    TokenWaitInfo wi = new TokenWaitInfo();\r\n                    wi.Handle = ThreadPool.RegisterWaitForSingleObject(\r\n                        tokenResetEvent,\r\n                        async (state, timedOut) =&amp;gt;\r\n                        {\r\n                            if (!timedOut)\r\n                            {\r\n                                TokenWaitInfo wi = (TokenWaitInfo)state;\r\n                                if (wi.Handle != null)\r\n                                {\r\n                                    wi.Handle.Unregister(null);\r\n                                }\r\n                            }\r\n                            else\r\n                            {\r\n                                try\r\n                                {\r\n                                    \/\/ Take a lock to ensure no other threads are updating the SharePoint Access token at this time\r\n                                    await semaphoreSlimTokens.WaitAsync().ConfigureAwait(false);\r\n                                    RemoveTokenFromCache(resourceUri, tokenCache);\r\n                                    Console.WriteLine($&quot;Cached token for resource {resourceUri.DnsSafeHost} and user {userPrincipalName} expired&quot;);\r\n                                }\r\n                                catch (Exception ex)\r\n                                {\r\n                                    Console.WriteLine($&quot;Something went wrong during cache token invalidation: {ex.Message}&quot;);\r\n                                    RemoveTokenFromCache(resourceUri, tokenCache);\r\n                                }\r\n                                finally\r\n                                {\r\n                                    semaphoreSlimTokens.Release();\r\n                                }\r\n                            }\r\n                        },\r\n                        wi,\r\n                        (uint)CalculateThreadSleep(accessToken).TotalMilliseconds,\r\n                        true\r\n                    );\r\n\r\n                    return accessToken;\r\n\r\n                }\r\n                finally\r\n                {\r\n                    semaphoreSlimTokens.Release();\r\n                }\r\n            }\r\n            else\r\n            {\r\n                Console.WriteLine($&quot;Returning token from cache for resource {resourceUri.DnsSafeHost} and user {userPrincipalName}&quot;);\r\n                return accessTokenFromCache;\r\n            }\r\n        }\r\n\r\n        private async Task&amp;lt;string&amp;gt; AcquireTokenAsync(Uri resourceUri, string username, string password)\r\n        {\r\n            string resource = $&quot;{resourceUri.Scheme}:\/\/{resourceUri.DnsSafeHost}&quot;;\r\n\r\n            var clientId = defaultAADAppId;\r\n            var body = $&quot;resource={resource}&amp;amp;client_id={clientId}&amp;amp;grant_type=password&amp;amp;username={HttpUtility.UrlEncode(username)}&amp;amp;password={HttpUtility.UrlEncode(password)}&quot;;\r\n            using (var stringContent = new StringContent(body, Encoding.UTF8, &quot;application\/x-www-form-urlencoded&quot;))\r\n            {\r\n\r\n                var result = await httpClient.PostAsync(tokenEndpoint, stringContent).ContinueWith((response) =&amp;gt;\r\n                {\r\n                    return response.Result.Content.ReadAsStringAsync().Result;\r\n                }).ConfigureAwait(false);\r\n\r\n                var tokenResult = JsonSerializer.Deserialize&amp;lt;JsonElement&amp;gt;(result);\r\n                var token = tokenResult.GetProperty(&quot;access_token&quot;).GetString();\r\n                return token;\r\n            }\r\n        }\r\n\r\n        private static string TokenFromCache(Uri web, ConcurrentDictionary&amp;lt;string, string&amp;gt; tokenCache)\r\n        {\r\n            if (tokenCache.TryGetValue(web.DnsSafeHost, out string accessToken))\r\n            {\r\n                return accessToken;\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        private static void AddTokenToCache(Uri web, ConcurrentDictionary&amp;lt;string, string&amp;gt; tokenCache, string newAccessToken)\r\n        {\r\n            if (tokenCache.TryGetValue(web.DnsSafeHost, out string currentAccessToken))\r\n            {\r\n                tokenCache.TryUpdate(web.DnsSafeHost, newAccessToken, currentAccessToken);\r\n            }\r\n            else\r\n            {\r\n                tokenCache.TryAdd(web.DnsSafeHost, newAccessToken);\r\n            }\r\n        }\r\n\r\n        private static void RemoveTokenFromCache(Uri web, ConcurrentDictionary&amp;lt;string, string&amp;gt; tokenCache)\r\n        {\r\n            tokenCache.TryRemove(web.DnsSafeHost, out string currentAccessToken);\r\n        }\r\n\r\n        private static TimeSpan CalculateThreadSleep(string accessToken)\r\n        {\r\n            var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(accessToken);\r\n            var lease = GetAccessTokenLease(token.ValidTo);\r\n            lease = TimeSpan.FromSeconds(lease.TotalSeconds - TimeSpan.FromMinutes(5).TotalSeconds &amp;gt; 0 ? lease.TotalSeconds - TimeSpan.FromMinutes(5).TotalSeconds : lease.TotalSeconds);\r\n            return lease;\r\n        }\r\n\r\n        private static TimeSpan GetAccessTokenLease(DateTime expiresOn)\r\n        {\r\n            DateTime now = DateTime.UtcNow;\r\n            DateTime expires = expiresOn.Kind == DateTimeKind.Utc ? expiresOn : TimeZoneInfo.ConvertTimeToUtc(expiresOn);\r\n            TimeSpan lease = expires - now;\r\n            return lease;\r\n        }\r\n\r\n        protected virtual void Dispose(bool disposing)\r\n        {\r\n            if (!disposedValue)\r\n            {\r\n                if (disposing)\r\n                {\r\n                    if (tokenResetEvent != null)\r\n                    {\r\n                        tokenResetEvent.Set();\r\n                        tokenResetEvent.Dispose();\r\n                    }\r\n                }\r\n\r\n                disposedValue = true;\r\n            }\r\n        }\r\n\r\n        public void Dispose()\r\n        {\r\n            \/\/ Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method\r\n            Dispose(disposing: true);\r\n            GC.SuppressFinalize(this);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<ul>\n<li>Con esta clase ya podemos obtener un Token valido y hacer consultas contra SharePoint. Por ejemplo:<\/li>\n<\/ul>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n public static async Task  Main(string&#x5B;] args)\r\n        {\r\n            Console.WriteLine(&quot;Introduce el tenant&quot;);\r\n            var tenant = Console.ReadLine();\r\n            Console.WriteLine(&quot;Introduce el usuario&quot;);\r\n            var user = Console.ReadLine();\r\n            Console.WriteLine(&quot;Introduce el passworkd&quot;);\r\n            var rawPassword = Console.ReadLine();\r\n            Uri site = new Uri($&quot;https:\/\/{tenant}.sharepoint.com\/&quot;);\r\n            \r\n            SecureString password = new SecureString();\r\n            foreach (char c in rawPassword) password.AppendChar(c);\r\n            \r\n            using (var authenticationManager = new AuthenticationManager())\r\n            using (var context = authenticationManager.GetContext(site, user, password))\r\n            {\r\n                context.Load(context.Web, p =&amp;gt; p.Title);\r\n                await context.ExecuteQueryAsync();\r\n                Console.WriteLine($&quot;Title: {context.Web.Title}&quot;);\r\n            }\r\n        }\r\n<\/pre>\n<p>y el resultado seria el siguiente<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/csom-net-core\/consola.PNG\" alt=\"dar permisos SharePoint\" \/><\/p>\n<h1 id=\"conclusiones\">Conclusiones<\/h1>\n<p>Que CSOM lo podamos utilizar en NET Standard es un <strong>gran paso para todos los desarrolladores de SharePoint. <\/strong>Con la llegada de .NET 5 y los cambios que implica, era cuesti\u00f3n de tiempo que acabara sucediendo, sin embargo su adelanto es algo de gran ayuda para todos los desarrolladores de Office. A nivel de aprendizaje los m\u00e9todos son exactamente iguales y por lo tanto no requiere de ning\u00fan aprendizaje extra.<\/p>\n<p>Happy codding!<\/p>\n<h1 id=\"codigo-fuente-en-github\">C\u00f3digo Fuente en Github<\/h1>\n<p><a href=\"https:\/\/github.com\/AdrianDiaz81\/Example-CSOM-NET-Standar\">https:\/\/github.com\/AdrianDiaz81\/Example-CSOM-NET-Standar<\/a><\/p>\n<h1 id=\"referencias\">Referencias<\/h1>\n<p><a href=\"https:\/\/docs.microsoft.com\/es-es\/sharepoint\/dev\/sp-add-ins\/using-csom-for-dotnet-standard\">https:\/\/docs.microsoft.com\/es-es\/sharepoint\/dev\/sp-add-ins\/using-csom-for-dotnet-standard<\/a><\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content --><span class=\"et_bloom_bottom_trigger\"><\/span>","protected":false},"excerpt":{"rendered":"<p>A finales de junio, se public\u00f3 una versi\u00f3n estable y oficial de uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: CSOM para .NET Standard, o lo que es lo mismo, la librer\u00eda Cliente para &hellip; <a href=\"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/sharepoint-csom-ya-disponible-en-net-standard\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":8,"featured_media":3339,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[191,142],"tags":[],"class_list":["post-3338","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-sharepoint-2016"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v18.2.1 (Yoast SEO v28.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SharePoint CSOM ya disponible en .NET Standard | ENCAMINA<\/title>\n<meta name=\"description\" content=\"A finales de Junio, se public\u00f3 en una versi\u00f3n estable y oficial, uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: CSOM para .NET Standard, o lo que es lo mismo: la librer\u00eda Cliente para poder acceder a SharePoint.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"SharePoint CSOM ya disponible en .NET Standard | ENCAMINA\" \/>\n<meta name=\"twitter:description\" content=\"A finales de Junio, se public\u00f3 en una versi\u00f3n estable y oficial, uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: CSOM para .NET Standard, o lo que es lo mismo: la librer\u00eda Cliente para poder acceder a SharePoint.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Adri\u00e1n D\u00edaz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/sharepoint-csom-ya-disponible-en-net-standard\\\/\"},\"author\":{\"name\":\"Adri\u00e1n D\u00edaz\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#\\\/schema\\\/person\\\/c9bfaede1bfba9564bb7f500788782bb\"},\"headline\":\"SharePoint CSOM ya disponible en .NET Standard\",\"datePublished\":\"2020-09-10T12:23:16+00:00\",\"dateModified\":\"2020-09-10T14:24:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/sharepoint-csom-ya-disponible-en-net-standard\\\/\"},\"wordCount\":2077,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/09\\\/art\u00edculo-Adri.jpg\",\"articleSection\":[\".NET\",\"sharepoint 2016\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/sharepoint-csom-ya-disponible-en-net-standard\\\/\",\"url\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/\",\"name\":\"SharePoint CSOM ya disponible en .NET Standard | ENCAMINA\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/09\\\/art\u00edculo-Adri.jpg\",\"datePublished\":\"2020-09-10T12:23:16+00:00\",\"dateModified\":\"2020-09-10T14:24:11+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#\\\/schema\\\/person\\\/c9bfaede1bfba9564bb7f500788782bb\"},\"description\":\"A finales de Junio, se public\u00f3 en una versi\u00f3n estable y oficial, uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: CSOM para .NET Standard, o lo que es lo mismo: la librer\u00eda Cliente para poder acceder a SharePoint.\",\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/sharepoint-csom-netcore\\\/#primaryimage\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/09\\\/art\u00edculo-Adri.jpg\",\"contentUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/09\\\/art\u00edculo-Adri.jpg\",\"width\":1115,\"height\":801},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#website\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/\",\"name\":\"Desarrollando sobre SharePoint\",\"description\":\"Arquitectura, buenas pr\u00e1cticas y desarrollo sobre la nueva herramienta de Microsoft SharePoint 2016\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#\\\/schema\\\/person\\\/c9bfaede1bfba9564bb7f500788782bb\",\"name\":\"Adri\u00e1n D\u00edaz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g\",\"caption\":\"Adri\u00e1n D\u00edaz\"},\"description\":\"Adri\u00e1n D\u00edaz es Ingeniero Inform\u00e1tico por la Universidad Polit\u00e9cnica de Valencia. Es MVP de Microsoft en la categor\u00eda Office Development desde 2014, MCPD de SharePoint 2010, Microsoft Active Profesional y Microsoft Comunity Contribuitor 2012. Cofundador del grupo de usuarios de SharePoint de Levante LevaPoint. Lleva desarrollando con tecnolog\u00edas Microsoft m\u00e1s de 10 a\u00f1os y desde hace 3 a\u00f1os est\u00e1 centrado en el desarrollo sobre SharePoint. Actualmente es Software &amp; Cloud Architect Lead en ENCAMINA.\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/author\\\/desarrollandosobresharepoint\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SharePoint CSOM ya disponible en .NET Standard | ENCAMINA","description":"A finales de Junio, se public\u00f3 en una versi\u00f3n estable y oficial, uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: CSOM para .NET Standard, o lo que es lo mismo: la librer\u00eda Cliente para poder acceder a SharePoint.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/","twitter_card":"summary_large_image","twitter_title":"SharePoint CSOM ya disponible en .NET Standard | ENCAMINA","twitter_description":"A finales de Junio, se public\u00f3 en una versi\u00f3n estable y oficial, uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: CSOM para .NET Standard, o lo que es lo mismo: la librer\u00eda Cliente para poder acceder a SharePoint.","twitter_image":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg","twitter_misc":{"Escrito por":"Adri\u00e1n D\u00edaz","Tiempo de lectura":"10 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/#article","isPartOf":{"@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/sharepoint-csom-ya-disponible-en-net-standard\/"},"author":{"name":"Adri\u00e1n D\u00edaz","@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#\/schema\/person\/c9bfaede1bfba9564bb7f500788782bb"},"headline":"SharePoint CSOM ya disponible en .NET Standard","datePublished":"2020-09-10T12:23:16+00:00","dateModified":"2020-09-10T14:24:11+00:00","mainEntityOfPage":{"@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/sharepoint-csom-ya-disponible-en-net-standard\/"},"wordCount":2077,"commentCount":0,"image":{"@id":"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg","articleSection":[".NET","sharepoint 2016"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/sharepoint-csom-ya-disponible-en-net-standard\/","url":"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/","name":"SharePoint CSOM ya disponible en .NET Standard | ENCAMINA","isPartOf":{"@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/#primaryimage"},"image":{"@id":"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg","datePublished":"2020-09-10T12:23:16+00:00","dateModified":"2020-09-10T14:24:11+00:00","author":{"@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#\/schema\/person\/c9bfaede1bfba9564bb7f500788782bb"},"description":"A finales de Junio, se public\u00f3 en una versi\u00f3n estable y oficial, uno de los grandes requerimientos de los desarrolladores de Office en los \u00faltimos a\u00f1os: CSOM para .NET Standard, o lo que es lo mismo: la librer\u00eda Cliente para poder acceder a SharePoint.","inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.theavenger.dev\/posts\/sharepoint-csom-netcore\/#primaryimage","url":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg","contentUrl":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/09\/art\u00edculo-Adri.jpg","width":1115,"height":801},{"@type":"WebSite","@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#website","url":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/","name":"Desarrollando sobre SharePoint","description":"Arquitectura, buenas pr\u00e1cticas y desarrollo sobre la nueva herramienta de Microsoft SharePoint 2016","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Person","@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#\/schema\/person\/c9bfaede1bfba9564bb7f500788782bb","name":"Adri\u00e1n D\u00edaz","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/secure.gravatar.com\/avatar\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g","caption":"Adri\u00e1n D\u00edaz"},"description":"Adri\u00e1n D\u00edaz es Ingeniero Inform\u00e1tico por la Universidad Polit\u00e9cnica de Valencia. Es MVP de Microsoft en la categor\u00eda Office Development desde 2014, MCPD de SharePoint 2010, Microsoft Active Profesional y Microsoft Comunity Contribuitor 2012. Cofundador del grupo de usuarios de SharePoint de Levante LevaPoint. Lleva desarrollando con tecnolog\u00edas Microsoft m\u00e1s de 10 a\u00f1os y desde hace 3 a\u00f1os est\u00e1 centrado en el desarrollo sobre SharePoint. Actualmente es Software &amp; Cloud Architect Lead en ENCAMINA.","url":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/author\/desarrollandosobresharepoint\/"}]}},"_links":{"self":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/posts\/3338","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/comments?post=3338"}],"version-history":[{"count":0,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/posts\/3338\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/media\/3339"}],"wp:attachment":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/media?parent=3338"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/categories?post=3338"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/tags?post=3338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}