Runtime: Admite la distribución de un solo archivo

Creado en 5 oct. 2018  ·  225Comentarios  ·  Fuente: dotnet/runtime

Este problema realiza un seguimiento del progreso en la función de distribución de un solo archivo de .NET Core 3.0.
Aquí está el documento de diseño y el plan de preparación para la función.

area-Single-File

Comentario más útil

Se espera que el primer inicio sea mucho más lento: extrae la aplicación en el disco, por lo que hay mucho IO.

Esto nunca debería haber sucedido, haces que la experiencia del usuario sea horrible POR DISEÑO, elección horrible, así es como haces que los usuarios odien la tecnología que el desarrollador está usando para ellos.

Como mencionó @Safirion , estamos trabajando en la próxima mejora para un solo archivo, que debería ejecutar la mayor parte del código administrado directamente desde el .exe (sin extracción en el disco). Sin embargo, todavía no puedo prometer un tren de lanzamiento.

¿Por qué lanzar esto oficialmente ahora si va a cambiar pronto? debe marcarse como vista previa/experimental

en mi opinión, esto es una pérdida de tiempo y recursos, concéntrese en la compilación AOT y la sacudida de árboles, ponga todos sus recursos allí, deténgase con los hacks

Todos 225 comentarios

Por interés, ¿cómo se compara esta iniciativa con CoreRT? ¿Parecen esfuerzos similares ?

¿Está relacionado con el ' código de usuario posiblemente nativo ', es decir, esto aún permitirá que el código se compile con JIT, no solo con AOT?

Además, supongo que los componentes de tiempo de ejecución (" Código nativo (tiempo de ejecución, host, partes nativas del marco... ") serán los del repositorio de CoreCLR.

Estás haciendo grandes preguntas, pero dado que esto aún es temprano en el diseño, aún no tengo grandes respuestas.

Por interés, ¿cómo se compara esta iniciativa con CoreRT? ¿Parecen esfuerzos similares?

Es probable que haya resultados algo similares (un solo archivo), pero el diseño puede tener diferentes características de rendimiento o funciones que funcionan o no. Por ejemplo, un diseño posible podría ser esencialmente concatenar todos los archivos en una aplicación independiente de .NET Core en un solo archivo. Eso es 10s de MB y podría comenzar más lentamente, pero por otro lado, permitiría todas las capacidades de CoreCLR, incluida la carga de complementos, emisión de reflexión y diagnósticos avanzados. CoreRT podría considerarse el otro extremo del espectro: tiene MB de un solo dígito y tiene un tiempo de inicio muy rápido, pero al no tener un JIT, no puede cargar complementos ni usar emisión de reflexión y el tiempo de compilación es más lento que la mayoría. Los desarrolladores de NET están acostumbrados. Actualmente tiene algunas otras limitaciones que podrían mejorar con el tiempo, pero podrían no ser mejores con .NET Core 3.0 (posiblemente requiera anotaciones para la reflexión, faltan algunos escenarios de interoperabilidad, diagnósticos limitados en Linux). También hay ideas en algún lugar entre los dos. Si la gente tiene concesiones que les gustaría hacer/evitar, tendríamos curiosidad por saber sobre ellas.

¿Está relacionado con el 'código de usuario posiblemente nativo', es decir, esto aún permitirá que el código se compile con JIT, no solo con AOT?

Por "código de usuario nativo", quise decir que su aplicación podría tener algún código nativo de C++ (ya sea escrito por usted o por un componente de terceros). Puede haber límites en lo que podemos hacer con ese código: si está compilado en un .dll, la única forma de ejecutarlo es fuera del disco; si es un .lib, podría ser posible vincularlo, pero eso trae otras complicaciones.

Además, supongo que los componentes de tiempo de ejecución ('Código nativo (tiempo de ejecución, host, partes nativas del marco...') serán los del repositorio de CoreCLR.

En base a todo lo anterior, descubriremos qué repositorios están involucrados. Las "partes nativas del marco" incluirían archivos nativos CoreFX como ClrCompression y Unix PAL.

Una distribución de un solo archivo de esta manera, incluso si tiene un tiempo de inicio ligeramente más lento, puede ser invaluable para facilitar la implementación. Preferiría tener la capacidad de tener todo el poder que verme obligado a renunciar a algo de eso.

Algunos escenarios que nos interesan. ¿Cómo funcionaría esto en términos de plataforma cruzada?
Supongo que tendremos un "archivo" separado por plataforma.

Con respecto al código nativo, ¿cómo podría elegir diferentes componentes nativos según la plataforma?

Algunos escenarios que nos interesan. ¿Cómo funcionaría esto en términos de plataforma cruzada?
Supongo que tendremos un "archivo" separado por plataforma.
Con respecto al código nativo, ¿cómo podría elegir diferentes componentes nativos según la plataforma?

@ayende , estoy citando el comentario de @morganbr :

un diseño posible podría ser esencialmente concatenar todos los archivos en una aplicación independiente de .NET Core en un solo archivo.

La historia multiplataforma actual para aplicaciones autónomas es crear un paquete de implementación por plataforma a la que le gustaría apuntar, porque envía la aplicación con el tiempo de ejecución, que es específico de la plataforma.

@morganbr Le agradezco que se haya tomado el tiempo para proporcionar una respuesta tan detallada

Estaré interesado en ver a dónde va el diseño, esta es una iniciativa realmente interesante.

Tengo algunas preguntas para las personas que deseen utilizar un solo archivo. Sus respuestas nos ayudarán a reducir nuestras opciones:

  1. ¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)
  2. ¿Tu aplicación incluye código C++/nativo (no .NET)?
  3. ¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?
  4. ¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?
  5. ¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?
  6. ¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?
  7. ¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?
  8. ¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?
  1. Consola/aplicación de interfaz de usuario en todas las plataformas.
  2. Tal vez como un componente de terceros.
  3. Posiblemente sí.
  4. Sí, especialmente si hay un sistema simple similar a ClickOnce.
  5. Se puede tolerar cierta desaceleración inicial. ¿Puede el punto 3 ayudar con eso?
  6. Depende de los activos. Hello world debe tener un tamaño del orden de MB.
  7. No importa si es solo producción.
  8. ¿Te gusta incluir en la lista blanca las cosas reflejadas? Si.

@morganbr , ¿piensa que es mejor hacer estas preguntas a un público más amplio? es decir, ¿más amplio que las personas que conocen este problema de GitHub?

Por ejemplo, un diseño posible podría ser esencialmente concatenar todos los archivos en una aplicación independiente de .NET Core en un solo archivo.

Mirando a comprimirlo; o usando un sistema de archivos comprimidos en el archivo?

@tpetrina , gracias! El punto 3 cubre un par de ángulos de diseño:

  1. La sacudida del árbol no va bien con la carga de complementos que el agitador del árbol no ha visto, ya que podría eliminar el código en el que se basa el complemento.
  2. CoreRT actualmente no tiene una forma de cargar complementos
    El punto 5 trata más sobre si optimizaríamos el tamaño o el tiempo de inicio (y cuánto)
    Punto 8, sí, estaba pensando principalmente en cosas de reflexión.

@TheBlueSky , también nos hemos puesto en contacto con otras personas, pero es útil recibir aportes de las personas apasionadas de la comunidad de GitHub.

@benaadams , la compresión está sobre la mesa, pero actualmente la considero ortogonal al diseño general. La experimentación ligera sugiere que comprimir puede obtener una reducción de tamaño del 50% a costa de varios segundos de tiempo de inicio (y tiempo de construcción). Para mí, ese es un intercambio lo suficientemente radical como para que, si lo hacemos, debería ser opcional.

@morganbr varios segundos de tiempo de inicio cuando se usa compresión? Encuentro eso difícil de creer cuando considero que UPX afirma velocidades de descompresión de

~10 MB/seg en un antiguo Pentium 133, ~200 MB/seg en un Athlon XP 2000+.

@morganbr , para mí las respuestas son:

1) Servicio (aplicación de consola que ejecuta Kestrel, básicamente). Ejecutándose como Windows Service/Linux Daemon o en Docker.
2) Sí
3) Sí, generalmente se administran ensamblajes con AssemblyContext.LoadFrom . Estos son proporcionados por el usuario final.
4) Sí, eso se espera. De hecho, ya agrupamos todo el marco de todos modos, por lo que no hay cambios desde esa perspectiva.
5) Como servicio, no nos importa mucho el tiempo de inicio. 5 segundos sería razonable.
6) 75 MB es probablemente el límite. Mucho depende del tamaño comprimido real, ya que todos los paquetes se entregan comprimidos.
7) Para compilaciones de lanzamiento, se aceptan tiempos de compilación más largos (incluso mucho más largos).
8) Sí, absolutamente. El tamaño no importa tanto, pero más pequeño es mejor.

Algo que no vi mencionado y es muy importante es la depuración de esto.
Espero que esto no destroce los rastros de la pila, y nos gustaría poder incluir archivos pdb o algún tipo de símbolos de depuración.

Acerca de la compresión, tenga en cuenta el hecho de que, en casi todos los casos, el mecanismo de entrega real ya está comprimido.
Por ejemplo, paquetes nuget.
Los usuarios también están bastante versados ​​​​en descomprimir cosas, por lo que no es un gran problema.
Creo que puedes hacer compresión en el costado.

¡Gracias, @ayende! Tienes razón en que debería haber mencionado la depuración. Creo que solo hay algunas formas menores en que la depuración podría verse afectada:

  1. Puede que no sea posible usar Editar y Continuar en un solo archivo (debido a que se necesita una forma de reconstruir y recargar el ensamblaje original)
  2. La compilación de un solo archivo puede producir un PDB o algunos otros archivos que se requieren para la depuración más allá de los que vienen con sus ensamblajes.
  3. Si se usa CoreRT, puede tener algunas funciones de depuración que se completan con el tiempo (especialmente en Linux/Mac).

Cuando dice "incluir archivos pdb", ¿quiere esos _dentro_ del archivo único o simplemente la capacidad de generarlos y guardarlos en caso de que necesite depurar la compilación de un solo archivo?

1) No es un problema para nosotros. E&C no es relevante aquí, ya que es probable que solo se use para la implementación real, no para el día a día.
2) Idealmente, tenemos un solo archivo para todo, incluidos los PDB, no un archivo y un conjunto de pdbs al lado. Ya existe la opción PDB incrustada, si eso funcionara, sería genial.
3) Cuando hablo de depuración, me refiero más al tiempo de producción que a la conexión de un depurador en vivo. Más específicamente, apilar información de seguimiento, incluidos los números de archivo y línea, poder resolver símbolos al leer el volcado, etc.

  1. Principalmente servicios pero algo de interfaz de usuario
  2. Algunos lo hacen, pero esto no sería urgente.
  3. unos segundos esta bien
  4. No nos importa. La suma del tamaño de dll está bien
  5. Idealmente no
  6. El tamaño no es de primordial importancia para nosotros

Otra pregunta para nosotros es si también podría hacer esto para componentes individuales (quizás incluso en etapas). Por ejemplo, tenemos bibliotecas DLL que usan muchas dependencias. Si pudiéramos empaquetarlos, nos ahorraríamos mucho dolor en la administración de versiones, etc. Si estos a su vez pudieran empaquetarse en un exe, ¿sería aún mejor?

  1. Servicios y algo de interfaz de usuario.
  2. No en este momento.
  3. Si. Idealmente, complementos que podrían cargarse desde una carpeta y recargarse en tiempo de ejecución.
  4. No es un problema siempre y cuando no presionemos 10-15+.
  5. Suma del tamaño de DLL, o similar.
  6. Si. Para una producción, el tiempo de compilación no es realmente un problema siempre que las compilaciones de depuración/prueba se construyan razonablemente rápido.
  7. Depende, pero la opción sería útil.
  1. Servicio e interfaz de usuario.
  2. A veces.
  3. Sí, por lo general.
  4. Si.
  5. Lo mejor es que sean menos de 5 segundos.
  6. La interfaz de usuario es de menos de 5 segundos, el servicio no importa.
  7. El tiempo de construcción no es importante, y el efecto de optimización es el más importante.
  8. Si.

@tpetrina @ayende @bencyoung @Kosyne @expcat respondió que sí a la pregunta 3 ("¿Su aplicación cargaría complementos u otros dll externos que no incluyó originalmente en la compilación de su aplicación?") - ¿Puede decirnos más sobre su uso? ¿caso?

El principal punto de venta de una distribución de un solo archivo es que solo hay un archivo para distribuir. Si su aplicación tiene complementos en archivos separados, ¿qué valor obtendría de una distribución de un solo archivo que tiene varios archivos de todos modos? ¿Por qué es mejor "app.exe+plugin1.dll+plugin2.dll" que "app.exe+coreclr.dll+clrjit.dll+...+plugin1.dll+plugin2.dll"?

app.exe + 300+ dlls - que es el estado actual hoy en día es realmente incómodo.
app.exe + 1-5 dlls que generalmente son definidos por el propio usuario es mucho más fácil.

Nuestro escenario es que permitimos ciertas extensiones por parte del usuario, por lo que normalmente solo implementaríamos un solo exe y el usuario puede agregar funcionalidad adicional según sea necesario.

No es tanto que _planeemos_ hacer eso, sino que queremos _ser capaces_ de hacerlo si surge la necesidad.

@ayende De acuerdo, lo mismo con nosotros.

Además, si pudiéramos hacerlo a nivel de dll, podríamos empaquetar las dependencias dentro de nuestros ensamblajes para que no entren en conflicto con los ensamblajes del cliente. Es decir, al elegir una versión de NewtonSoft.Json, actualmente la está definiendo para todos los programas, complementos y ensamblajes de terceros en la misma carpeta, pero si pudiera incrustarlo, los terceros tienen flexibilidad y aumentan la compatibilidad de versiones.

De acuerdo con @ayende .

¡Gracias a todos por sus respuestas! Según la cantidad de personas que usarán código nativo o necesitarán cargar complementos, creemos que el enfoque más compatible que podemos administrar es el lugar correcto para comenzar. Para hacer eso, utilizaremos un enfoque de "empaquetar y extraer".

Esta será una herramienta que esencialmente integra toda la aplicación y los archivos de .NET como recursos en un ejecutable extractor. Cuando se ejecuta el ejecutable, extraerá todos esos archivos en un directorio temporal y luego se ejecutará como si la aplicación se publicara como una aplicación que no es de un solo archivo. No comenzará con la compresión, pero potencialmente podríamos agregarla en el futuro si se justifica.

El detalle más complicado de este plan es dónde extraer los archivos. Tenemos que tener en cuenta varios escenarios:

  • Primer lanzamiento: la aplicación solo necesita extraerse en algún lugar del disco
  • Lanzamientos posteriores: para evitar pagar el costo de extracción (probablemente varios segundos) en cada lanzamiento, sería preferible que la ubicación de extracción sea determinista y permita que el segundo lanzamiento use archivos extraídos por el primer lanzamiento.
  • Actualizar: si se inicia una nueva versión de la aplicación, no debería usar los archivos extraídos por una versión anterior. (Lo contrario también es cierto; es posible que las personas deseen ejecutar varias versiones una al lado de la otra). Eso sugiere que la ruta determinista debe basarse en el contenido de la aplicación.
  • Desinstalar: los usuarios deberían poder encontrar los directorios extraídos para eliminarlos si lo desean.
  • Tolerancia a fallas: si un primer lanzamiento falla después de extraer parcialmente su contenido, un segundo lanzamiento debe rehacer la extracción.
  • Ejecución elevada: los procesos ejecutados como administrador solo deben ejecutarse desde ubicaciones en las que el administrador pueda escribir para evitar que los procesos de baja integridad los manipulen.
  • Ejecución no elevada: los procesos que se ejecutan sin privilegios de administrador deben ejecutarse desde ubicaciones en las que el usuario puede escribir

Creo que podemos dar cuenta de todos ellos mediante la construcción de un camino que incorpore:

  1. Un directorio base conocido (p. ej., %LOCALAPPDATA%\dotnetApps en Windows y ubicaciones de perfil de usuario en otros sistemas operativos)
  2. Un subdirectorio separado para elevados
  3. Identidad de la aplicación (tal vez solo el nombre del exe)
  4. Un identificador de versión. La versión numérica probablemente sea útil, pero insuficiente ya que también necesita incorporar versiones de dependencia exactas. Un guid o hash por compilación podría ser apropiado.

Juntos, podrían parecerse a c:\users\username\AppData\Local\dotnetApps\elevated\MyCoolApp\1.0.0.0_abc123\MyCoolApp.dll
(Donde la aplicación se llama MyCoolApp, su número de versión es 1.0.0.0 y su hash/guid es abc123 y se lanzó elevado).

También se requerirá trabajo para incrustar archivos en el extractor. En Windows, podemos simplemente usar recursos nativos, pero Linux y Mac pueden necesitar un trabajo personalizado.

Finalmente, esto también puede necesitar ajustes en el host (para encontrar archivos extraídos) y diagnósticos (para encontrar el DAC u otros archivos).

CC @swaroop-sridhar @jeffschwMSFT @vitek-karas

Siento que esta cura es peor que la enfermedad. Si tenemos que lidiar con directorios externos (diferentes entre los sistemas operativos), actualizaciones, desinstalaciones y similares, eso va en contra de mi razón para desear esta función en primer lugar (mantener todo simple, portátil, autónomo y limpio).

Si tiene que ser absolutamente de esta manera, para mi proyecto, preferiría un solo ejecutable principal y los archivos desempaquetados para vivir en un directorio junto a ese ejecutable, o posiblemente la capacidad de decidir a dónde va ese directorio.

Sin embargo, solo soy yo, tengo curiosidad por saber de otros también.

Tengo que estar de acuerdo aquí, usar un directorio diferente puede tener muchos problemas emocionantes, por ejemplo, coloca un archivo de configuración junto con el exe y este exe no se selecciona porque el directorio "real" está en otro lugar.
El espacio en disco podría ser un problema, también los bloqueos de archivos aleatorios debido a las políticas de acceso, etc.
Me gustaría usar esta función, pero no si agrega una serie de modos de falla que son imposibles de detectar antes.

De acuerdo con @Kosyne : la solución inicial propuesta parece simplemente automatizar una especie de "instalador". Si ese fuera el límite del problema que estamos tratando de resolver con un solo ejecutivo, creo que todos simplemente habríamos realizado esa automatización nosotros mismos.

El objetivo clave de la propuesta de ejecución única debe ser poder ejecutar un ejecutable en un sistema no administrado. ¿Quién sabe si incluso tiene acceso de escritura a cualquier directorio de "instalación" de destino elegido? Ciertamente, tampoco debería dejar artefactos de sí mismo después del lanzamiento (no de forma predeterminada).

Como una pequeña modificación a la propuesta existente para satisfacer lo anterior: ¿No podríamos descomprimir en la memoria y ejecutar desde allí?

De acuerdo con el resto de los comentarios. Descomprimir a otra ubicación es algo que _ya_ está disponible.
Podemos tener un zip autoextraíble que ejecutará los valores extraídos con bastante facilidad. Eso no responde a muchas de las preocupaciones que esto pretende responder y es solo otro nombre para la instalación.

La ubicación del archivo es importante. Por ejemplo, en nuestro caso, eso significaría:

  • Encontrar el archivo de configuración (que generamos sobre la marcha si no está allí y dejamos que el usuario lo personalice)
  • Encontrar / crear archivos de datos, que generalmente es relativo al exe de origen.
  • El PID/nombre del proceso debe coincidir, para garantizar un seguimiento/soporte adecuado.

Uno de nuestros usuarios necesita ejecutar nuestro software desde un DVD, cómo funciona eso, en un sistema que en realidad no _tiene_ un HD para ejecutarse.

Estoy de acuerdo en que sería mejor hacer todo en la memoria. Y la preocupación sobre el tiempo de inicio no es tan grande, estaría bien pagar esto por cada reinicio, o hacer un paso manualmente para aliviar eso si es necesario.

Otro problema aquí es el tamaño real. Si esto es solo (efectivamente) un instalador, eso significa que estamos hablando de tamaños de archivo para una aplicación razonable en los 100 MB, ¿no?

Parece que construir la solución propuesta no requiere (muchos, si es que los hay) cambios de CLR. Los usuarios ya pueden construir una solución como esa. No tiene sentido agregar esto a CoreCLR. Especialmente, dado que el caso de uso para esto es bastante estrecho y específico.

@GSPP Esto parece básicamente algo que puedo hacer hoy con 7z-Extra , estoy de acuerdo en que si este es el caso, sería mejor _no_ tenerlo en absoluto.

Lo siento, llegué tarde a esta fiesta, llegué aquí después de seguir un enlace publicado en un boleto duplicado que estaba rastreando.
Después de leer los últimos comentarios aquí, lamento ver que está considerando empacar y extraer. Esto parece una exageración, ¿por qué no comenzar con la capacidad de implementar SFA para aplicaciones de consola básicas? Me parece que debería ser posible crear una aplicación de consola rudimentaria con alguna red, IO y algunas dependencias externas (nuget, etc.) que se encuentra en un solo archivo.
Supongo que lo que intento decir es que, en lugar de recopilar los requisitos de todos, recopile los requisitos de nadie y, en su lugar, comience poco a poco con una primera iteración que tenga sentido para todos y produzca resultados rápidamente.

Esto parece básicamente algo que puedo hacer hoy con 7z-Extra

Tiene razón en que hoy en día existen varias soluciones independientes del entorno de programación para abordar este problema. Otro ejemplo de muchos: https://www.boxedapp.com/exe_bundle.html

El valor agregado aquí sería la integración en las herramientas dotnet para que incluso los usuarios no expertos puedan hacerlo fácilmente. Los usuarios expertos pueden hacer esto hoy uniendo las herramientas existentes como usted ha señalado.

Personalmente, estoy de acuerdo con usted en que no está claro que estemos tomando la decisión correcta aquí. Tuvimos muchas discusiones sobre esto dentro del equipo central.

Poner un pasante en él y salir con una herramienta global (que se recomienda, pero no es compatible) funcionaría igual de bien, y también puede ser bastante fácil de instalar.

Efectivamente, estamos hablando de dotnet publish-single-file y eso haría todo lo necesario detrás de escena.

No veo nada que realmente requiera el marco o el tiempo de ejecución para admitir este escenario, y al hacer que esto sea algo que esté explícitamente fuera del marco, permitirá a los usuarios mucha más libertad sobre cómo modificar esto.
No hay "necesidad" de obtener un PR (con toda la ceremonia asociada, pacto regresivo, seguridad, etc.) que obtendría si desea realizar un cambio en el marco.
Simplemente bifurca un proyecto secundario común y utilícelo.

Tenga en cuenta que, por mucho que me gustaría esta función, preferiría no tener algo dentro (lo que significa que _siempre_ estará dentro) que se pueda hacer igual de bien desde el exterior.

Quiero hacer una pregunta de mayor nivel: ¿Cuál es la principal motivación de los clientes que desean la distribución en un solo archivo?
es principalmente:

  1. ¿Embalaje? Si es así, independientemente de si la solución es una bandeja de entrada o una herramienta de terceros, ¿qué características son las más importantes?
    a) Tiempo de inicio (más allá de la primera ejecución)
    b) Capacidad para ejecutarse en entornos no escribibles
    c) No dejar archivos tras la carrera
    d) No tener que ejecutar un instalador
    2) Rendimiento?
    a) Velocidad (enlace estático de código nativo, evitando múltiples cargas de biblioteca, optimizaciones entre módulos, etc.)
    b) Tamaño del código (solo necesita un certificado, sacudida de árboles, etc.)
    3) ¿Algún otro?

Me preocupa un poco que algunos consideren que esta característica no es tan importante, o al menos podría no ser un buen objetivo para incluir en el conjunto de características principales aquí. Me gustaría reiterar que creo que sería inmensamente poderoso para cualquier aplicación que actúe como un servicio o submódulo de una aplicación más grande. Uno del que usted, el autor, puede que ni siquiera sea el desarrollador. No quiero tener que pasar los requisitos de dependencia que solo se pueden resolver con instalaciones (automáticas o de otro tipo), o artefactos posteriores a la ejecución en el disco que pueden necesitar una elevación de seguridad adicional por parte del usuario, etc.
En este momento, .NET simplemente no es una buena opción para este problema de nicho. Pero podría ser (y debería ser IMO).

El ejecutable compilado debe:

  • Empaquetar todas las dependencias relevantes
  • No tener artefactos de ejecución (sin escrituras en disco)

Re @swaroop-sridhar Me atrevo a decir que cada aplicación tendrá su propio orden único de necesidades de rendimiento, por lo que me imagino que el mejor enfoque después de abordar la solución principal es elegir la fruta al alcance de la mano e ir desde allí.

@swaroop-sridhar Para mí, se trata de empaque y facilidad de uso para el usuario final.
No hay necesidad de lidiar con la instalación de todo el sistema, simplemente haga clic y ejecute.

Esto es importante porque permitimos que nuestro software se incruste y un complemento de un solo archivo es mucho más fácil de administrar.

@strich El punto sobre la incrustación es bueno. Normalmente se nos utiliza como un componente en una arquitectura de microservicios, y la reducción de la sobrecarga de implementación lo hará más fácil.

El problema no es lo que sea o no, esta es una característica importante. El problema es cualquiera que sea la solución propuesta (esencialmente comprimir las cosas, en este punto) se requiere que esté _en el núcleo_.
Las cosas que están en el núcleo tienen un estándar mucho más alto para los cambios. Sería mejor tener esto como una herramienta externa, porque es más fácil de modificar y ampliar.

Para ser honesto, preferiría ver una mejor opción en conjunto. Por ejemplo, es posible cargar dlls desde la memoria, en lugar de archivos (requiere algo de trabajo, pero es posible).
Si eso sucede, puede ejecutar _todo_ el asunto puramente desde la memoria, y el desempaquetado se realiza en la memoria pura y sin golpes de disco.

Eso es algo que debería ir en el núcleo, porque muy probablemente requerirá modificaciones en el tiempo de ejecución para habilitarlo.
Y eso sería valioso en sí mismo y fuera de él. Y no es algo que podamos hacer actualmente.

Entonces, un buen ejemplo es mirar la experiencia de las herramientas Go como Cónsul de Hashicorp. Un solo archivo exe que puede colocar en cualquier máquina y ejecutar. Sin instaladores, sin copiar carpetas, sin buscar archivos de configuración en listas de cientos de archivos, solo una experiencia de usuario final realmente agradable.

Para nosotros, no estoy seguro de que el enfoque en memoria funcione, ya que también nos gustaría que esto funcione para los complementos DLL (por lo que eliminar un complemento también sería un solo archivo en lugar de todas sus dependencias), pero cualquier progreso sería sé bueno. Hemos analizado Fody.Costura y funciona bien para algunas cosas, pero hemos tenido problemas con .NET Core para eso.

Entonces, un buen ejemplo es mirar la experiencia de las herramientas Go como Consul de Hashicorp.

Eh, para herramientas como consul, la solución ideal sería corert, no esta improvisación de autoextracción.

@mikedn ¿Por qué es eso? No veo qué tiene que ver la compilación AOT o JIT con el método de implementación.

Quiero secundar las palabras de @strich , las implementaciones de un solo archivo serían una bocanada de aire fresco para las implementaciones de arquitectura de microservicios, así como para cualquier aplicación de consola que sea, o al menos comience su vida como, una pequeña herramienta con línea de comando interruptores

¿Porque eso? No veo qué tiene que ver la compilación AOT o JIT con el método de implementación.

Porque le brinda exactamente lo que desea: un solo archivo exe que puede colocar en cualquier máquina (bueno, cualquier máquina que tenga un sistema operativo adecuado, después de todo es un archivo nativo) y ejecutar. También tiende a usar menos recursos, lo que para agentes como el cónsul es algo bueno. Es más o menos el equivalente de lo que le ofrece Go, más que una solución de extracción automática.

@mikedn supongo, pero

1) ¡Realmente no existe todavía en forma de producción (hasta donde yo sé)!
2) Usamos muchas características dinámicas (generación de IL, reflexión arbitraria)
3) Todavía queremos poder agregar complementos (de nuevo, idealmente compactados)

Mira, ya que este problema se trataba de preguntarle a la gente qué quiere, ¡solo estamos dando nuestra opinión! Realmente no queremos tener que cambiar a un modelo de tiempo de ejecución diferente solo para obtener este beneficio. Para mí son preocupaciones ortogonales

No veo qué tiene que ver la compilación AOT o JIT con el método de implementación.

Sin un JIT, es más fácil que cosas como la historia de depuración sean lo suficientemente buenas. La parte JIT hace que el problema sea más difícil, por lo que no lo encontrará en Go. Esto es ingeniería, por lo que envía más ingenieros al problema más difícil y vive con la nueva complejidad, o lo reduce a otro lugar. El autoextractor se trata de reducir el alcance porque la cantidad de ingenieros con las habilidades necesarias es limitada.

Las personas con proyectos que se parecen más a los proyectos Go (sin requisitos JIT) pueden estar bastante contentas con CoreRT, si les parece bien la etiqueta "experimental". Es bastante fácil de probar en estos días. Utiliza el mismo recolector de basura, generador de código, CoreFX y la mayor parte de CoreLib que el CoreCLR completo, y produce ejecutables pequeños (megabytes de un solo dígito) que son autónomos.

¡Realmente no existe todavía en forma de producción (hasta donde yo sé)!

Sí, mi comentario estaba dirigido principalmente a personas con EM : grin:. Tienen todos estos proyectos/ideas paralelos, relacionados y en curso (corert, ilinker) y ahora agregan uno más, esta cosa de autoextracción que, como muchos ya señalaron, es un poco "meh, podemos hacer eso". nosotros mismos" tipo de cosas. Y también tiene inconvenientes, como extraer archivos a un directorio "oculto".

Usamos muchas características dinámicas (generación de IL, reflexión arbitraria)

Eso es algo que la comunidad en su conjunto podría querer pensar dos veces. Claro que es útil poder hacer eso, pero entra en conflicto con otros deseos, como la implementación de un solo archivo. Todavía puede obtener la implementación de un solo archivo, pero eso tiende a tener un costo: un archivo bastante grande. Si estás de acuerdo con eso, entonces está perfectamente bien. Pero en mi experiencia, cuanto más grande es el archivo, menos útil se vuelve el aspecto de "archivo único".

@MichalStrehovsky seguro, hay diferentes opciones. Sin embargo, para nosotros no podemos usar experimental (convencer de que era hora de pasar a .NET Core fue bastante difícil) y tampoco creo que la extracción a una carpeta temporal funcione en nuestro caso. Sin embargo, en el peor de los casos, seguimos como estamos y no usamos esta función.

Sin embargo, es algo que nos gustaría si fuera como nos gustaría :)

@mikedn Estoy de acuerdo. Múltiples soluciones paralelas son aún más confusas. Creo que nuestra solución ideal sería algún tipo de enfoque súper ILLinker/weaver, pero estoy feliz de dejar que esto funcione y ver dónde terminamos.

Estoy muy, muy entusiasmado con el aterrizaje de esta funcionalidad, pero, para ser sincero, tampoco estoy entusiasmado con la propuesta inicial que publicaste en @morganbr. Mis respuestas a la lista de preguntas que planteó son similares a las que otros publicaron (por lo que creo que hay un conjunto común de capacidades deseadas), pero en mi humilde opinión, la solución propuesta de 'desempaquetar en disco' no es en absoluto lo que espero ver. implementado y como otros dijeron sería casi peor que la 'enfermedad'. @jkotas

Estoy de acuerdo con @strich y @ayende
El ejecutable compilado debe:
Empaquetar todas las dependencias relevantes
No tener artefactos de ejecución (sin escrituras en disco)

Cargar .dlls desde la memoria en lugar del disco puede no ser fácil, pero ese es el tipo de capacidades que, en mi opinión, valdrían la profunda experiencia de los desarrolladores de bajo nivel de MSFT (y luego aprovechar en CoreClr) frente a la propuesta anterior que podría implementarse como una herramienta externa (y ya la tiene, consulte https://github.com/dgiagio/warp). Si esto se lograra, me pregunto ¿cuánta diferencia de tiempo habría entre la primera ejecución y las siguientes? Para inspiración/ejemplo, creo que Linux 3.17+ tiene memfd_create que puede ser usado por dlopen.

En otro tema, me pregunto si el requisito para admitir complementos es sobreindexar la propuesta de diseño. ¿Valdría la pena hacer que esta funcionalidad sea opcional, de modo que solo las personas que necesitan esta capacidad incurran en las posibles sanciones (falta de sacudidas de árboles, etc.) y todos los demás (¿una mayoría significativa?)

Retrocediendo @swaroop-sridhar @MichalStrehovsky , puedo ver dos casos de uso amplio que podrían tener objetivos/deseos lo suficientemente diferentes como para dificultar acomodar a todos con una solución:

  • Idealmente, las herramientas de CLI quieren una ejecución rápida cada vez, pequeña distribución; ¿Quizás se ajuste mejor a CoreRT?
  • El microservicio probablemente puede tolerar una primera ejecución más larga (idealmente <1 s), distribuible más grande, a cambio de una funcionalidad más rica como JIT y características de código dinámico.

Espero que este braindump tenga algún sentido, no estoy tratando de ser un idiota, solo brindo comentarios porque estoy muy interesado en este tema. ¡Gracias por todo su arduo trabajo y por solicitar la opinión de la comunidad! :)

Acerca de los complementos.
Básicamente, lo único que me gustaría es _no_ ser bloqueado en llamadas Assembly.LoadFrom o LoadLibrary .
No necesito nada más y puedo hacer el resto por mi cuenta.

@ayende ¿Puede explicar con un poco más de detalle qué quiere decir con "estar bloqueado en LoadFrom y demás"?

Por ejemplo, algunas de las sugerencias para esto incluían CoreRT, lo que significaba que (probablemente) no podríamos simplemente cargar un dll administrado.
Pero siempre que pueda proporcionar una ruta a un dll administrado y obtener un ensamblado o llamar a LoadLibrary en un dll nativo, estoy de acuerdo con que este sea el mecanismo del complemento.

Digo esto para dejar en claro que los escenarios de los complementos no son algo que se deba _considerar_, sino algo que no se deba _bloquear_.

Pasé un tiempo investigando el código y, a primera vista, parece que debería ser _posible_ (hablando de Windows solo para simplificar las cosas):

  • Empaquete todo el CoreCLR en un exec (digamos que es un recurso incrustado o algo así).
  • Enumere los dll nativos, llame algo como MemoryModule (https://github.com/fancycode/MemoryModule) para cargarlos en la memoria
  • Invoque el tiempo de ejecución y cargue un ensamblado desde la memoria.

Voy a suponer que esto _no_ es tan simple como eso. Por ejemplo, ICLRRuntimeHost2::ExecuteAssembly no proporciona ninguna forma de darle un búfer, solo un archivo en el disco.
Eso lo convierte en el primer (de lo que estoy seguro será muchos) impedimento para que realmente funcione.

Estoy bastante seguro de que hay una gran cantidad de código que podría referirse a cosas relacionadas como archivos que pueden fallar, pero este es el tipo de cosas a las que me refiero cuando digo que quiero un solo archivo exec y por qué ese tipo de la solución debe realizarse en CoreCLR y no externamente (como en el ejemplo zip).

llamar a algo como MemoryModule

Los archivos binarios cargados mediante MemoryModule no son diagnosticables (p. ej., ninguno de los depuradores, perfiladores, etc. habituales funcionarán en ellos) y MemoryModule omite todas las medidas de seguridad integradas del sistema operativo (p. ej., antivirus, etc.). No es algo que podamos enviar como una solución compatible.

Voy a suponer que esto no es tan simple como eso.

Correcto, se necesitarían nuevas API (tanto administradas como no administradas) para admitir la ejecución desde un paquete de un solo archivo no expandido. Los programas y bibliotecas existentes no "simplemente funcionarían".

¿Podría ser razonable solicitar que la interfaz de análisis antimalware sea
implementado por los ingenieros de Windows en MemoryModule como lo fue recientemente para
todos los ensamblajes .net, incluidos los cargados desde mem?

https://twitter.com/WDSecurity/status/1047380732031762432?s=19

EDITAR: Hmm MemoryModule sonaba como algo integrado en el sistema operativo para cargar módulos nativos, pero aparentemente no lo es, probablemente sea razón suficiente para ignorar mi sugerencia anterior

El miércoles, 5 de diciembre de 2018, 01:46, enero Kotas [email protected] escribió:

llamar a algo como MemoryModule

Los archivos binarios cargados mediante MemoryModule no son diagnosticables (p. ej., ninguno de
los depuradores regulares, generadores de perfiles, etc.) trabajarán en ellos, y MemoryModule
omite todas las medidas de seguridad integradas del sistema operativo (por ejemplo, antivirus, etc.). No lo es
algo que podríamos enviar como solución compatible.

Voy a suponer que esto no es tan simple como eso.

Correcto, se necesitarían nuevas API (tanto administradas como no administradas) para
Admite la ejecución desde un paquete de un solo archivo no expandido. La existencia
los programas y las bibliotecas no "simplemente funcionarían".


Estás recibiendo esto porque estás suscrito a este hilo.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/dotnet/coreclr/issues/20287#issuecomment-444314969 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AEBfudvVHxpbeKa-L_vTQjbnNZZsn6Meks5u1xdlgaJpZM4XK-X_
.

Gracias por todos los comentarios.
Publicaremos un plan actualizado para admitir la distribución de un solo archivo en breve.

@NinoFloris ver dotnet/coreclr#21370

Me doy cuenta de que llegué tarde a esta discusión, así que pido disculpas si esto no ayuda.

Para reiterar lo que dijo @mikedn , puede ser confuso tener todas estas soluciones paralelas, y plantea la pregunta de dónde estará el enfoque de MS en el futuro. El hecho de que el brillante trabajo realizado en CoreRT todavía se considere experimental sin una hoja de ruta oficial y con una funcionalidad similar implementada en CoreCLR (CPAOT, ahora publicación de un solo archivo) dificulta la toma de decisiones comerciales basadas en la tecnología. No me gustaría volver a elegir el caballo equivocado (Silverlight...).

¿Por qué no seguir con el tiempo de ejecución brillante en CoreRT y enfocar el trabajo en incorporar un JIT (y expandir el trabajo del intérprete hasta que esté listo) en CoreRT para aquellos que desean capacidades de marco completas mientras aún tienen código nativo creado para ellos? ¿No sería posible, en el caso de querer capacidades JIT, mantener los metadatos y JIT dentro de un ejecutable compilado de forma nativa de CoreRT?
¿No sería este el mejor de todos los mundos? P.ej. tendría los ejecutables más pequeños, el tiempo de inicio más rápido, las limitaciones del código AOT en CoreRT podrían expandirse al tener un JIT en su lugar y mantener los metadatos y el código IL para aquellos que desean conservar la funcionalidad completa del marco.
En mi opinión, el enfoque debe estar en la "mejor solución posible" en lugar de en la funcionalidad a corto plazo que podría distraer la atención de los objetivos a largo plazo.

Tal vez me equivoque, pero creo que la publicación de un solo archivo como parte de CoreCLR distraería aún más a los clientes de CoreRT, que en muchos de los casos sería una solución potencialmente mejor para ellos. P.ej. si esto se marca como "ahora puede publicar su código .NET como un solo archivo", pero está creando archivos enormes, sufrirá en el rendimiento de inicio, etc. entonces puedo ver que la gente comienza a quejarse de este "tiempo de ejecución .NET inflado" una vez más . Si bien .NET en realidad ya tiene una solución brillante para exactamente eso en CoreRT, aunque carece del soporte oficial/compromiso oficial del producto para llegar hasta el final.

Quizás mi preocupación sea principalmente que me gustaría ver menos productos paralelos (nuevamente citando a @mikedn) y más énfasis en comprometerse profundamente, ampliar y apoyar a los que están aquí (incluido el intercambio de hojas de ruta).

menos productos paralelos

Tenemos un solo producto: .NET Core. CoreRT no es un producto separado y nunca lo será. Se trata de agregar opciones a este producto. Estos son algunos ejemplos de las opciones que tenemos hoy: estación de trabajo GC y servidor GC; Publicación de aplicaciones autónomas frente a publicación de aplicaciones dependientes del marco.

@jkotas Lo entiendo, y estoy completamente de acuerdo en que agregar opciones suele ser excelente. Si reemplaza mi uso de la palabra "productos" con "opciones/soluciones", sigo manteniendo mi preocupación de no saber completamente si el compromiso de nuestro producto con CoreRT como una opción/solución dentro del producto general .NET Core es algo que puede apostar con seguridad a ser apoyado en muchos años por venir. Imagínese cómo sería si las API hicieran cambios importantes e impredecibles a lo largo del tiempo y quedaran repentinamente obsoletas sin que usted sepa si puede confiar o no en una API para permanecer allí. Para una entidad que no sea MS, las herramientas/opciones que forman parte del producto se sienten de la misma manera. Dependemos de varias capacidades de CoreRT que no podríamos hacer (al menos actualmente) con CoreCLR (una de ellas es la capacidad de proteger nuestros ejecutables con PACE y eliminar muchos metadatos, IL, etc., enlace estático fácil, comprensión más fácil de la plataforma subyacente, posibilidad de crear ofuscación directamente en el compilador, etc.). Básicamente, creo que el trabajo suyo y el de Michal y otros en CoreRT debería priorizarse, ya que, en mi opinión, es una de las mejores cosas que ha sucedido en el ecosistema .NET desde que se diseñó por primera vez. Cada vez que se habla de una nueva herramienta/opción que, internamente, podría verse como una competencia con CoreRT en lugar de la opción CoreRT para completarse y extenderse, me parece una asignación incorrecta de recursos. Lo siento, no fue mi intención prolongar la discusión, solo quería asegurarme de que entendiera cuánto se aprecia el trabajo de CoreRT y que algunos de nosotros creemos que debería ser el futuro de la plataforma.
Me abstendré de contaminar más esta discusión. Deseando todo lo mejor para los equipos y esperando con ansias lo que se te ocurra, estoy seguro de que será genial.

@christianscheuer Sus comentarios sobre este problema y sobre otros problemas relacionados con CoreRT han sido muy valiosos. No estás contaminando esta discusión en absoluto.

se habla de una nueva herramienta/opción que luego internamente podría verse como una competencia con CoreRT

Entre el equipo central, hemos hablado sobre varias opciones diferentes, ambiciosas o más locas. No considero que "descomprimir en disco" sea un competidor importante con CoreRT full AOT. Cada uno se dirige a un segmento diferente de usuarios/aplicaciones de .NET.

Nuestro equipo de administración de productos, que recopila datos de muchos canales diferentes (incluidos los problemas de github o las conversaciones cara a cara con los clientes), sugirió que la mejor inversión es una solución como la que se propone aquí. Todavía estamos validando que tengamos todos los datos sobre este derecho y que tenga el resultado deseado.

No puedo prometerles cuándo se enviará la tecnología CoreRT como parte del producto .NET Core compatible en este momento. Sé que tiene fortalezas únicas y estoy seguro de que vamos a ofrecer una solución compatible como esa para el segmento de usuarios importantes de .NET que eventualmente se beneficiarán de ella.

La distribución de un solo archivo tiene sentido si:

  • No afecta el tiempo de inicio (de lo contrario, solo las aplicaciones más pequeñas podrán usarlo)
  • Actúa como un VFS (Sistema de archivos virtual) Le permite acceder a ensamblajes y recursos como si fueran desde el disco, desde la carpeta de la aplicación).
  • No afecta la "parcheabilidad" de la aplicación. IE: Microsoft debería poder aplicar parches a los ensamblajes críticos, incluso si están integrados, proporcionando anulaciones en otro lugar, a nivel del sistema.

Los ensamblajes como recursos incrustados, extraídos y copiados en una carpeta temporal no son una solución necesaria de Microsoft. Puede ser implementado fácilmente por cualquier cliente que lo necesite.

Se necesita una solución de archivo único "verdadera" y proporcionaría mucho valor.

@jkotas tus comentarios me parecen verdaderos. Me resultaría difícil convencer a los desarrolladores de .NET de mi empresa (LOB/backoffice/integraciones) para cambiar a CoreRT porque sería un gran salto para ellos (especialmente dada la etiqueta Experimental), pero pueden ver el valor en un solución relativamente simple (de usar) para Core como este hilo está discutiendo. Gracias

@ popcatalin81 De hecho, no estoy de acuerdo con sus puntos aquí.

El tiempo de inicio no es significativo para muchas aplicaciones. Con gusto intercambiaré un aumento del 50 % al 100 % en el tiempo de inicio de cualquier servicio de larga duración con el fin de reducir la complejidad operativa de su implementación.

Incluso si agregamos 30 segundos al tiempo de inicio de un servicio, eso no es realmente significativo a largo plazo para los servicios.
Para las aplicaciones orientadas al usuario, es probable que sea un factor decisivo, pero hasta que salga 3.0, casi todas las aplicaciones CoreCLR son consolas o servicios.

No es que CoreCLR ya tenga un modo en el que puede agrupar el marco con su aplicación (implementación autónoma).
En nuestro caso (RavenDB), _confiamos_ en eso para varios propósitos. Primero, la capacidad de elegir nuestro propio marco independientemente de lo que estén usando nuestros usuarios. Este es un _mayor_ beneficio para nosotros, ya que significa que no necesitamos usar el marco instalado globalmente y, por lo tanto, no estamos atados a lo que el administrador decidiera que sería el marco (solíamos tener en cuenta que estaríamos ejecutando en .NET 4.0 a veces, incluso años después de que saliera 4.5, por ejemplo, y eso era un fastidio).
Otro aspecto importante es que podemos ejecutar con _nuestra propia_ bifurcación del framework. Esto es muy útil si nos encontramos con cosas que debemos cambiar.

Como parte de eso, nos hacemos cargo de los ciclos de parches y no queremos que nadie más se meta con eso.

No me _importa_ VFS, pero no creo que sea necesario. Y estoy perfectamente de acuerdo con tener que pasar por una API dedicada/saltar algunos aros para llegar a los ensamblajes/dlls nativos/recursos que se combinan de esta manera.

@briacht me señaló este tema durante dos días, así que llegué MUY tarde a la discusión.
¡Solo quiero agregar mis 2 centavos!

Primero mis respuestas a las preguntas de @morganbr :

  1. Aplicación de Windows, mezclando WPF y WinForms.
  2. Actualmente no
  3. Sí, usando Assembly.Load en diferentes variaciones
  4. Depende si esto es una penalización que hay en cada arranque. Sí, si son unos pocos milisegundos, pero 5 segundos: no. Si es una sola vez, 5 segundos no hay problema.
  5. 50 MB ya es bastante grande en comparación con <2 MB... pero si esto significa que se incluye el tiempo de ejecución de dotnet... OK. Tal vez pueda proporcionar una descarga con y sin.
  6. El tiempo de lanzamiento no importa directamente, pero no debería molestar al proveedor de CI al usar una gran cantidad de CPU durante un período de tiempo prolongado.
  7. ¡SÍ!

La aplicación de la que hablo es Greenshot, la versión lanzada actual prácticamente todavía está dirigida a .NET Framework 2.0 (sí, en serio) pero funciona sin problemas en la versión más reciente (¡buena compatibilidad con versiones anteriores)! La descarga, incluido el instalador pero sin .NET Framework, es de alrededor de 1,7 MB. El directorio desde el que se inicia contiene 1 .exe y 4 .dlls, también hay 11 complementos en un subdirectorio.

Estaba leyendo los comentarios anteriores, y muchos de ellos suenan como si quisieras algo con la funcionalidad para la que usaría un instalador. Esto tiene algo de sentido, ya que actualmente no existe una solución independiente de la plataforma.

Estaba discutiendo el tema actual con algunas personas en Microsoft en agosto, mi enfoque principal era vincular todo para reducir el tamaño y la complejidad de la aplicación para la implementación y también reducir la carga del ensamblaje, lo que lleva MUCHO tiempo durante el inicio. de mi aplicación.

Con la próxima versión de Greenshot, que apunta a .NET Framework 4.7.1 y dotnet core 3.0 en paralelo, la descarga resultante para dotnet core 3.0 actualmente tiene alrededor de 103 dlls (!!!), un exe y 15 complementos . El tamaño total es de alrededor de 37 MB y el archivo más grande es MahApps.Metro.IconPacks.dll (¡12 MB!), que contiene la mayoría de los íconos que usamos, lo que probablemente representa alrededor del 4 % del archivo. Lo mismo con muchos de los otros dlls, ¡supongo que, en general, el 50% del uso del código es mucho!

Si el usuario no desea instalar la aplicación, simplemente descargue un .zip y busque el ejecutable entre alrededor de 118 archivos... ¡no es realmente una experiencia agradable! El tamaño es alrededor de 35 MB (17x) más grande, entonces, ¿dónde está el beneficio para el usuario?

En los meses previos a dotnet core 3.0, estaba usando Fody.Costura para hacer más o menos lo que se describe aquí. ¡Embalaje durante la construcción y desembalaje al inicio! Incluso hizo posible un solo ejecutable sin extraer los archivos pirateando un pero. Pero también causó bastantes problemas, por lo que esta no es mi solución preferida.

Espero una solución más o menos estándar de la que pueda decir: simplemente funciona ™
Tal vez tenga sentido definir una estructura de carpetas estándar, de modo que podamos colocar los archivos ejecutables, Léame, de licencia, etc. en la raíz y tener diferentes directorios "conocidos" para diferentes archivos (dotnet core, dependencias, etc.). Esto podría facilitar el trabajo de las herramientas y ofrecer una funcionalidad en la que todos puedan decidir qué quieren usar y qué no. A veces, incluso ejecutar zip en el directorio resuelve algunos problemas.

Tener una solución similar a Fody.Costury es definitivamente en algún momento que podría utilizar para simplificar la implementación de Greenshot, pero no reduce directamente el tamaño y el tiempo de carga. ¡Así que espero que pase algo de tiempo aquí también!

@ayende Por favor, permítame estar en desacuerdo con usted también :)

Si bien son verdaderos servicios, las aplicaciones web y, en general, las aplicaciones de ejecución prolongada basadas en servidor no se ven afectadas por un costo de inicio único, al mismo tiempo, estas aplicaciones no son las que obtienen más beneficios del modelo de distribución de un solo archivo. (Raven es una excepción, no la norma;))

En mi opinión, la distribución de un solo archivo está dirigida principalmente a aplicaciones y utilidades dirigidas a los usuarios. Usuarios que descargarán, copiarán, ejecutarán tales aplicaciones. Y en un futuro próximo, cuando.Net Core 3.0 ofrezca soporte para bibliotecas de interfaz de usuario, este modelo de distribución será bastante común. Sin embargo, debo enfatizar que este modelo no será adecuado para ninguna aplicación. Las principales aplicaciones seguirán utilizando un instalador.

Ahora la pregunta es, este modelo de ensamblajes incrustados copiados en carpetas temporales, ¿funcionará bien si se vuelve muy popular?

En mi opinión, estos son algunos problemas potenciales para el modelo actual:

  • Docenas de aplicaciones crean miles de archivos temporales con ensamblajes duplicados. Hay potencial para crear un lío aquí. (Inadvertido para los usuarios, pero sigue siendo un desastre)
  • Sin compresión, sin enlazador. Esto podría crear una desventaja para las aplicaciones de utilidades pequeñas en comparación con FDD o la compresión de eventos.
  • En realidad, podría dificultar las implementaciones del servidor en lugar de facilitarlas, por la siguiente razón: configuración posterior a la implementación con reemplazos de tokens. (¿Dónde va para encontrar la carpeta temporal para sobrescribir los archivos de configuración? ¿Le da al servicio acceso de escritura a su propia carpeta para crear el archivo de configuración allí? Esa es una seguridad no-no)

No estoy aquí para decir que este modelo no es óptimo para todo tipo de aplicaciones. Lo implementé con éxito y lo usé yo mismo en el pasado para full.Net Framework, y es una buena opción para ciertas aplicaciones.

Simplemente creo que la implementación óptima es la versión en la que un vinculador fusiona todos los ensamblajes en un solo archivo.

@popcatalin81 Un mundo con un único punto de vista es pobre. Y no soy tan arrogante como para pensar que mi modelo de implementación es el único que existe.

El caso que tengo en mente es el escenario de descarga y doble clic.
En este momento, tenemos que descomprimir y hacer clic en un script de shell para ejecutarlo, porque ingresar a un directorio con cientos de archivos y encontrar el correcto es una tarea ardua.

Acerca de la configuración en archivos temporales. Yo estaría muy en contra de eso. Los archivos de configuración son otras cosas visibles para el usuario que _deben_ residir justo al lado del archivo real que se está utilizando, no ocultos en algún lugar.
Ya vimos lo malo que era con los archivos IsolatedStorage cuando los usuarios los necesitaban.

En versiones anteriores de RavenDB, fusionamos muchas cosas para tener un diseño de directorio más simple y reducir la cantidad de archivos visibles, y eso tuvo un gran impacto en la usabilidad de nuestro software.

¿Esta función utilizará ILMerge? ¿Si no, porque no? Me gustaría educarme si hay una trampa.

No me gusta el enfoque propuesto de "empaquetar y extraer", especialmente la parte en la que extraería archivos en el disco. Es simple, pero tiene demasiados problemas. Todo debería funcionar desde "en la memoria" sin extraerlo al disco.

Creo que debería ser algo así como corert native compiler o Costura.Fody .

Opcionalmente, también debería intentar reducir el tamaño binario (eliminar referencias no utilizadas, IL muerto).

re

En los meses previos a dotnet core 3.0, estaba usando Fody.Costura para hacer más o menos lo que se describe aquí. ¡Embalaje durante la construcción y desembalaje al inicio!

tenga en cuenta que costura no "descomprime en disco" (por defecto). extrae (en la memoria) los ensamblajes incrustados de los recursos y los carga a través de bytes

Gracias por el contexto @SimonCropp , estamos explorando ambas opciones de descomprimir en disco y cargar desde una transmisión. Cubrir la carga de un flujo para IL puro puede ser posible en nuestra primera iteración.

@jeffschwMSFT Por cierto, el conjunto de funciones de ensamblajes que se fusionan sin problemas (y el movimiento de árboles opcional) es algo que me encantaría ver como ciudadano de primera clase. costura es uno de mis proyectos más populares, pero también uno que toma mucho tiempo para apoyar. así que si/cuando MS presente una alternativa (incluso como una versión beta), házmelo saber y pasaré un tiempo revisándolo y agregaré algo de "hay una alternativa de MS" al Léame de costura y a la descripción de Nuget.

aunque es poco probable, si necesita que libere parte del código en costura bajo una licencia diferente, solo hágamelo saber.

Gracias @SimonCropp a medida que comencemos a integrar mono/illinker en la cadena de herramientas de .NET Core, aceptaremos su oferta de revisión.

tenga en cuenta que costura no "descomprime en disco" (por defecto). extrae (en la memoria) los ensamblajes incrustados de los recursos y los carga a través de bytes

Aún mejor, creo que se carga a pedido usando el evento AppDomain.AssemblyResolve , por lo que el inicio no debería verse demasiado afectado, ya que solo cargará ensamblajes (en la memoria) cuando sea necesario.

Tarde para la conversación aquí. Disculpas si esto ya ha sido cubierto.

¿Podemos asumir que el artefacto aquí será determinista? ¿Por lo tanto, la misma compilación siempre producirá el mismo binario? Byte por byte. También sería útil poder distribuir un binario con una suma de verificación canónica que lo acompañe.

@morganbr Hay mucha lectura necesaria aquí. ¿Sería posible registrar las decisiones tomadas hasta el momento?

@edblackburn estamos elaborando un diseño actualizado basado en los comentarios. @swaroop-sridhar está impulsando el diseño ahora.

¿Esta función utilizará ILMerge? ¿Si no, porque no? Me gustaría educarme si hay una trampa.

@simplejackcoder ILMerge combina la IL de muchos ensamblajes en uno, pero en el proceso, pierde la identidad original de los ensamblajes combinados. Por lo tanto, cosas como usar la reflexión basada en nombres de ensamblados originales fallarán.

El objetivo de este esfuerzo no es fusionar ensamblajes, sino empaquetarlos mientras se mantiene la identidad del ensamblaje. Además, necesitamos empaquetar no solo los ensamblajes, sino también los archivos binarios nativos, los archivos de configuración, posiblemente el tiempo de ejecución y cualquier otra dependencia requerida por la aplicación.

Fusionar IL es una característica útil para las aplicaciones que pueden adaptarse a ella; es solo una característica diferente de este problema.

Se publica una revisión del diseño en https://github.com/dotnet/designs/pull/52
Continuemos la discusión sobre el PR de ahora en adelante.

Tengo algunas preguntas para las personas que deseen utilizar un solo archivo. Sus respuestas nos ayudarán a reducir nuestras opciones:

  1. ¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)
  2. ¿Tu aplicación incluye código C++/nativo (no .NET)?
  3. ¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?
  4. ¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?
  5. ¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?
  6. ¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?
  7. ¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?
  8. ¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?
  1. Nuestro caso de uso de dotnet/coreclr#1, por mucho, son aplicaciones de consola que son utilidades. Nos gustaría hacer una publicación para Windows o Linux y especificar --single-file para obtener un ejecutable. Para Windows esperaríamos que esto terminara en .exe , para Linux, sería un binario ejecutable.
  2. Por lo general, no, pero podría a través de un paquete NuGet sin que lo sepamos.
  3. Inicialmente no, pero sería una gran característica futura.
  4. Lo que sea que funcione
  5. Sí, si optimizó el tamaño resultante del ejecutable. Idealmente, puede ser una bandera para establecer el nivel de optimización usando --optimizing-level=5
  6. si, hasta cierto punto

Gracias @BlitzkriegSoftware.
Creo que el diseño propuesto aquí cubre su caso de uso. Eche un vistazo al diseño. Agradecemos sus comentarios.

Tengo algunas preguntas para las personas que deseen utilizar un solo archivo. Sus respuestas nos ayudarán a reducir nuestras opciones:

  1. ¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)
  2. ¿Tu aplicación incluye código C++/nativo (no .NET)?
  3. ¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?
  4. ¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?
  5. ¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?
  6. ¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?
  7. ¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?
  8. ¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?
  1. Aplicación WPF .Core 3.0
  2. Tal vez en un paquete nuget
  3. No
  4. Sí para 200-500 ms máx.
  5. No es importante siempre que no sea 2 o 3 veces más grande que el tamaño de la carpeta de publicación original
  6. Es para producción, así que no es realmente importante.
  7. Sí, pero tiene la posibilidad de no hacerlo. Puede ser útil si el trabajo se refiere a una biblioteca de terceros.

Los comentarios que recibió fueron en gran parte para el desarrollo antes de 2019, que generalmente son servicios web, aplicaciones de consola y otros servicios lanzados en segundo plano. Pero ahora con .net core 3.0, necesitamos soluciones para aplicaciones WPF y UI. .Net Framework 4.8 no admitirá .Net Standard 2.1 y necesitamos una solución para reemplazar ILMerge que usamos hasta ahora para las aplicaciones WPF, ya que tenemos que actualizar nuestras aplicaciones de .net framework (marco inactivo) a .net core.

Un paquete autoextraíble claramente no es una buena solución como se explicó en otros comentarios anteriores para este tipo de programas.

  1. Principalmente aplicaciones CLI. Los pequeños servicios de Windows y la aplicación WPF ocasional también son interesantes. Para cosas web, la distribución de un solo archivo parece básicamente irrelevante. Por esta razón, el resto de esto está mayormente orientado a Windows; nuestro interés en Linux .NET Core está relacionado con las cosas de la web.
  2. A veces. Cuando lo hace, casi siempre es para bibliotecas de compresión. Si las cosas nativas no se empaquetaran, no sería el fin del mundo. Una buena solución para cosas puramente administradas que requerían la implementación de una dependencia nativa como un dll separado aún tendría valor.
  3. No, no en los casos en los que nos preocupamos por un solo archivo.
  4. Si.
  5. 200 ms es aproximadamente el límite antes de que las cosas se vuelvan molestas para que se inicie una CLI. > 1 segundo y es casi seguro que nos quedaremos con .NET Framework (ILMerge + ngen) o buscaremos otros lenguajes que compilan en un binario nativo con cualquier tiempo de ejecución necesario vinculado estáticamente. En muchos casos, estamos hablando de cosas que se implementó en C# porque una aplicación de C# ngen-ed integrada en realidad se inicia razonablemente rápido. Algunas de estas cosas son, en cuanto a la complejidad, razonables para implementar en un lenguaje de secuencias de comandos, pero tienden a tener costos iniciales significativos, especialmente si necesita incorporar un montón de módulos.
  6. Depende Más de 10 MB para hello world sería una venta difícil. Grandes también ejecutables tienden a tener costos de inicio no triviales. Incluso si el sistema operativo es teóricamente capaz de iniciar la ejecución sin leer todo, al menos en Windows, casi siempre hay algo que primero quiere obtener un hash para algún propósito de seguridad. Hablando de eso, esto de desempaquetar un montón de binarios a la cosa temporal va a volver loco a AV (Defender absolutamente incluido), en términos de utilización de recursos escaneando frenéticamente, al menos.
  7. Por supuesto. Me encantaría agregar un minuto o más a una compilación de lanzamiento si eso significa obtener algo que tenga un tamaño razonable y comience a ejecutarse rápidamente.
  8. Definitivamente.

Al leer la propuesta, no aborda ningún escenario que tengamos y que no usaríamos. Puede haber alguien a quien le resuelva un problema, pero no somos nosotros.

Parece que hay muchas cosas relevantes para escenarios como el nuestro en los que se está trabajando que simplemente no se han unido en una cadena de herramientas que en realidad se pueda usar/probablemente siga funcionando. Tal vez esto sea solo ignorancia de mi parte, pero trato de prestar atención y no me queda claro. Entre ILLink, Microsoft.Packaging.Tools.Trimming, CoreRT, .NET Native y lo que sea que suceda en este problema, parece que debería haber alguna forma de obtener un solo binario de tamaño razonable, de inicio rápido (¿posiblemente AoT?) fuera de .NET Core (y no para UWP).

  1. La distribución de un solo archivo sería muy útil para las aplicaciones https://github.com/AvaloniaUI/Avalonia (Windows, Linux, MacOS) y WPF (Windows). Tener un solo exe hace que las actualizaciones automáticas sean fáciles, por ejemplo, y en general es más conveniente tener un solo archivo en comparación con cientos de dlls.
  2. Sí (en el sentido de que hace referencia a bibliotecas nativas preconstruidas como sqlite y skia)
  3. No
  4. 200 ms probablemente esté bien. Tener un tiempo de inicio de 5 segundos para una aplicación GUI no está bien.
  5. realmente no importa
  6. Realmente no importa Podríamos construir un solo archivo solo para escenarios de producción.

Por favor, no vaya con el enfoque de paquete y extracción. Ya podríamos lograr esto usando herramientas de archivo.

Por favor, no vaya con el enfoque de paquete y extracción. Ya podríamos lograr esto usando herramientas de archivo.

No puedo estar más de acuerdo. Ya hay varias herramientas disponibles que hacen esto.

Gracias por los comentarios @Safirion , @mattpwhite , @x2bool , @thegreatco.
A partir de estos, veo una variedad de escenarios de uso (aplicaciones de consola, WPF, aplicaciones de GUI, etc.), pero los requisitos generales parecen similares:

  • Concéntrese en el tiempo de ejecución/inicio en lugar del tiempo de compilación.
  • Capacidad para reconstruir aplicaciones para futuras versiones/parches
  • Capacidad para ejecutarse directamente desde el paquete (especialmente para componentes puramente administrados).

Creo que estos son los requisitos que hemos tratado de abordar en el documento de diseño .

Por favor, no vaya con el enfoque de paquete y extracción

Sí, como se explica en este documento provisional , el objetivo es minimizar progresivamente la dependencia de la extracción de archivos.

Al leer la propuesta, no aborda ningún escenario que tengamos y que no usaríamos.

@mattpwhite , quería aclarar si cree que esta solución no funciona para usted en base a:

  • El enfoque basado en la autoextracción propuesto anteriormente en este elemento de trabajo, o
  • El diseño anotado en este documento
    Creo que el último documento trata de abordar el escenario que ha detallado. Gracias.

Parece que hay muchas cosas relevantes para escenarios como el nuestro en los que se está trabajando que simplemente no se han unido en una cadena de herramientas que en realidad se pueda usar/probablemente siga funcionando.

@mattpwhite , hay trabajo en curso para integrar ILLink (desplazamiento de árboles), crossgen (generación de código nativo listo para ejecutar) y aspectos de agrupación de un solo archivo en msbuild/dotnet CLI de manera simplificada para .net core 3. Una vez Una vez hecho esto, el uso de estas herramientas se puede lograr fácilmente (por ejemplo, establecer ciertas propiedades de msbuild).

Todas estas herramientas vienen con compensaciones. Por ejemplo, crossgen genera código nativo antes de tiempo, lo que ayuda al inicio, pero tiende a aumentar el tamaño de los archivos binarios. Al usar la opción de un solo archivo, las aplicaciones se pueden publicar en un solo archivo, pero esto puede ralentizar el inicio, porque los binarios nativos se derraman en el disco, etc.

@swaroop-sridhar, gracias por tomarse el tiempo para responder.

Quería aclarar si cree que esta solución no funciona para usted en función de

Parecía que la extracción todavía está en la imagen para cualquier cosa autónoma, y ​​el estado de crossgen (o cualquier otra cosa para reducir el tiempo JIT en el lanzamiento) no estaba claro para mí. Al leer el documento de puesta en escena que vincula el diseño actual, parecía que las cosas que harían esto más interesante para nosotros estaban más lejos. Teniendo en cuenta eso, pensé que seguiríamos atascados en el uso de .NET Framework para estos nichos durante algún tiempo. Puede que haya entendido mal.

Todas estas herramientas vienen con compensaciones. Por ejemplo, crossgen genera código nativo antes de tiempo, lo que ayuda al inicio, pero tiende a aumentar el tamaño de los archivos binarios.

Sí, entendido que algunos de estos son espadas de doble filo. Con la forma en que JIT ha funcionado tradicionalmente, ngen siempre ha sido una victoria para las aplicaciones CLI/GUI. Es posible que alguna combinación de compilación en niveles y el hecho de que cargar el tiempo de ejecución en sí no se amortiza necesariamente con muchos otros procesos de .NET Framework que se ejecutan en el mismo cuadro hace que eso sea menos claro en Core.

@swaroop-sridhar la gran preocupación que tengo con la propuesta actualmente aceptada es este paso

Los 216 archivos restantes se extraerán al disco al inicio.

Aparte del hecho de que "Hello World" parece requerir 216 archivos para ejecutarse, extraerlos al disco en alguna ubicación dificulta la eliminación de una aplicación de línea de comando simple. Cuando las personas eliminan una herramienta que no vino a través de un instalador, no esperan tener que buscar otros archivos para eliminarla por completo.

En mi humilde opinión, deberíamos apuntar a una experiencia de publicación similar a la de golang. Si bien requeriría crossgen para coincidir completamente con la experiencia de golang (y se podría argumentar que una coincidencia 1: 1 no es algo _bueno_, ya que perdemos el JIT y la compilación por niveles), un buena parte se puede lograr sin ella. He usado muchas herramientas a lo largo de los años para lograr una experiencia similar, y la más efectiva fueron los recursos integrados con un gancho en el cargador de ensamblaje (ILMerge era quisquilloso y Costura.Fody aún no existía). Lo que se describe en la propuesta ni siquiera replica completamente esa funcionalidad. .NET Core tiene un futuro muy sólido, pero su uso para desarrollar herramientas de línea de comandos es limitado siempre que necesitemos cargar cientos de dependencias o escupirlas en algún lugar del disco con algún código de arranque ondulado a mano.

Mi caso de uso de dotnet/coreclr#1 son las utilidades de línea de comando, un archivo, no preferiría extraerlo. Pero me gustaría señalar que dar una opción como parte de los interruptores de comando para todo-en-uno vs. todo-en-uno-autoextracción. En el caso de extracción automática, debe incluir un undo que limpie los archivos desempaquetados. En el primer caso, eliminar la utilidad significa eliminar un archivo que lo hace adecuado para residir en una carpeta de utilidades generales, mientras que en el segundo caso, la instalación debe tener su propia carpeta para facilitar la limpieza y evitar escenarios en los que la desinstalación elimina los archivos compartidos. Solo algunos pensamientos. Como dije, la utilidad de un archivo (no se necesita instalación) es mi caso de uso principal, ya que hago utilidades para proyectos (como herrero) con frecuencia. Pero puedo ver un caso de uso para ambos escenarios. Pero son diferentes .

Tengo algunas preguntas para las personas que deseen utilizar un solo archivo. Sus respuestas nos ayudarán a reducir nuestras opciones:

  1. ¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)
  2. ¿Tu aplicación incluye código C++/nativo (no .NET)?
  3. ¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?
  4. ¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?
  5. ¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?
  6. ¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?
  7. ¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?
  8. ¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?
  1. CLI (Windows, Linux, MacOS), WPF y WinForms.
  2. A veces.
  3. Sí, muchas veces y creo que se debe abordar el escenario en el que un complemento puede reutilizar una biblioteca compartida desde la aplicación principal.
  4. Si.
  5. ¡200-500 ms están bien!
  6. ¡Para una aplicación CLI simple sin muchas dependencias, 10 MB son suficientes (comprimidos)!
  7. ¡Sí definitivamente! ¡El tiempo de compilación (¡especialmente para compilaciones de lanzamiento!) no importa! ¡El tamaño de compresión y/o el cambio a la publicación de un solo archivo deberían ser opcionales!
  8. ¡Sí, por ejemplo, CoreRT!

En mi humilde opinión, deberíamos apuntar a una experiencia de publicación similar a la de golang.

@thegreatco : Sí, la compilación completa en código nativo es una buena opción para crear aplicaciones de un solo archivo. Los lenguajes como GO están construidos con compilación anticipada (AOT) como su modelo principal, lo que viene con ciertas limitaciones en las características dinámicas del lenguaje logradas a través de la compilación JIT.

CoreRT es la solución .Net Core para aplicaciones compiladas de AOT. Sin embargo, hasta que CoreRT esté disponible, estamos tratando de lograr aplicaciones de un solo archivo a través de otros medios en este problema.

Aparte del hecho de que "Hello World" parece requerir 216 archivos para ejecutarse,

Hay algunas opciones disponibles para reducir la cantidad de archivos necesarios para HelloWorld"

  • Cree una aplicación dependiente del marco, que solo necesita 3-4 archivos
  • Si necesitamos crear aplicaciones independientes, use ILLinker para reducir la cantidad de dependencias de archivos

extraerlos al disco en alguna ubicación dificulta la eliminación de una aplicación de línea de comando simple.

  • A medida que el desarrollo de la función de un solo archivo avanza hacia etapas posteriores, la cantidad de archivos que se transfieren al disco disminuirá e, idealmente, será cero para la mayoría de las aplicaciones. Pero en las etapas iniciales, se deberán derramar varios archivos (los que contienen código nativo).
  • La ubicación de los archivos volcados al disco siempre es determinista y configurable. Por lo tanto, los archivos derramados se pueden limpiar con un script sencillo. Pero estoy de acuerdo en que esto no es lo ideal.

Gracias por la aclaración @mattpwhite.

Sí, hasta las etapas posteriores del desarrollo de funciones, las aplicaciones independientes verán los archivos extraídos en el disco. Es posible que pueda usar algunas de las técnicas que escribí en el comentario anterior para mejorar la situación de sus aplicaciones.

Gracias por su respuesta @BlitzkriegSoftware.

Pero señalaría que dar una opción como parte de los interruptores de comando para todo-en-uno vs. todo-en-uno-autoextraíble

Si una aplicación publicada como un archivo único requiere extracción depende del contenido de la aplicación (por ejemplo, si contiene archivos nativos). El diseño del paquete proporciona algunas configuraciones para decidir si se deben extraer todos los archivos. Podemos agregar una propiedad para decir que la aplicación no debe usar la extracción de archivos en tiempo de ejecución.

<propertygroup>
    <SingleFileExtract> Never | Always | AsNeeded </SingleFileExtract>
</propertygroup>

El entendimiento aquí es: al compilar SingleFileExtract=Never, si la aplicación contiene archivos que solo se pueden manejar a través de la extracción (binarios nativos), la publicación en un solo archivo fallará.

En el caso de extracción automática, debe incluir un deshacer que limpie los archivos desempaquetados.

Suena razonable. La ubicación exacta de la extracción (si la hay) es determinista y configurable. Entonces, podemos tener un script para eliminar una aplicación y todas sus dependencias extraídas.

Gracias por tu respuesta @DoCode. Su escenario es interesante porque utiliza complementos.
Si los propios complementos tienen algunas dependencias (que no se comparten con la aplicación principal), ¿necesitaría/preferiría publicar el complemento también como un archivo único (con dependencias incrustadas)? Gracias.

Sí @swaroop-sridhar, ese es el objetivo. Creemos que en este caso el complemento debería incrustar sus dependencias. Solo las dependencias compartidas deberían haberse quedado fuera de la aplicación principal de un solo archivo.

Hoy, @madskristensen compartió una buena aclaración con Visual Studio y el popular paquete Newtonsoft.Json NuGet.

¡Tenemos las mismas situaciones en una situación similar a veces!

Gracias @DoCode. Planeamos abordar la característica de los complementos de un solo archivo, una vez que las aplicaciones de un solo archivo estén implementadas y estables. El documento de diseño habla sobre complementos aquí .

Gracias por el compromiso continuo en esta función @swaroop-sridhar, se agradece mucho. Tener un comando de deshacer será excelente especialmente para las etapas originales.

  1. ¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)
    -- Utilidades de línea de comandos (aplicaciones de consola)
  2. ¿Tu aplicación incluye código C++/nativo (no .NET)?
    -- No
  3. ¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?
    -- No Usualmente
  4. ¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?
    -- Sí
  5. ¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?
    -- < 1 segundo sería mi preferencia
  6. ¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?
    -- El tamaño no es importante
  7. ¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?
    -- 30 segundos
  8. ¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?
    -- Claro, si puede programarse o configurarse

1 - ¿Con qué tipo de aplicación probablemente la usarías? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)

  • Juegos
  • Herramientas de línea de comandos

2 - ¿Su aplicación incluye (no .NET) C++/código nativo?

3 - ¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?

Sí, pero ya con símbolos conocidos, no confío en la reflexión ya que es lenta

4 - ¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?

5 - ¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?

No, ya es un poco lento.

6 - ¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?

Depende del proyecto, pero para una herramienta de línea de comando simple, no espero que sea más grande que mbs de un solo dígito

7 - ¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?

Mientras no afecte el tiempo de desarrollo/iteración, estoy bien con un tiempo de compilación de lanzamiento más largo
Pero recuerde, las aplicaciones .net core ya se compilan durante más tiempo que las aplicaciones tradicionales de .net framework.

Esa tendencia de software mas lento cada año NO es aceptable, tenemos mejor hardware, no hay razón para esa lentitud

8 - ¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?

¡SÍ!

Realmente espero que la compilación de AOT con CoreRT funcione algún día para que podamos tener aplicaciones compiladas de forma nativa como golang y rust y otros lenguajes compilados de AOT. De manera similar a como lo hace Unity3D con IL2CPP.

@morganbr Aquí hay algunos aportes míos y de la gente con la que trabajo. Uso muchos lenguajes, pero principalmente C#, Go y Python.

¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)

Los programas ASP.NET Core y Console, principalmente en Linux, potencialmente algunas cargas de trabajo de Windows, dependiendo de si ML.NET satisface nuestras necesidades.

¿Tu aplicación incluye código C++/nativo (no .NET)?

Improbable en este punto.

¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?

Depende. Actualmente podemos extraer todas nuestras dependencias como paquetes, pero podría ver una situación en la que paguemos por una biblioteca comercial, lo que puede significar el uso de archivos DLL externos.

¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?

Absolutamente. Esta es una prioridad para nosotros.

¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?

Diría que cualquier cosa menos de 10 segundos está más que bien para mí. El tiempo de inicio generalmente no importa siempre que sea idempotente y predecible, es decir, las bibliotecas se cargan en el mismo orden, las variables se inicializan en el mismo orden, etc.

¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?

Más pequeño es mejor, principalmente para fines de distribución. La distribución podría ser binarios descargados por el usuario, imágenes de contenedores con el binario, etc.

¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio?

Claro, mientras sea más rápido que C/C++ y Java, debería ser aceptable.

¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?

Probablemente 30-90 segundos sería lo ideal, pero cualquier cosa por debajo de 3 minutos probablemente sea agradable. Más de 3 minutos para proyectos pequeños/medianos (1k-500k LOC) sería demasiado. 5 minutos para proyectos muy grandes (1M LOC) podría ser aceptable.

¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?

Depende. Si el trabajo adicional es agregar un código repetitivo que se puede crear en una plantilla, es probable que esté bien. Si no está claro, no es un trabajo sencillo, potencialmente no.

Gracias por la respuesta @mxplusb , @dark2201 , @RUSshy , @BlitzkriegSoftware

Creo que el diseño actual aborda sus escenarios en la mejor medida posible en ausencia de una compilación AOT pura. Si tiene alguna inquietud sobre el diseño, no dude en mencionarla.

Con respecto a tener un tiempo de inicio y un tiempo de compilación más bajos:
Las aplicaciones dependientes del marco tendrán un tiempo de inicio considerablemente menor (al menos en las etapas iniciales de la aparición de la función). El tiempo de compilación también es menor (porque es necesario incrustar menos archivos).
Me pondré en contacto con usted con las medidas de tiempo de inicio, rendimiento de compilación y tamaño de archivo tan pronto como se complete la primera iteración del desarrollo de características.

@swaroop-sridhar ¿Cuál es la línea de tiempo para eso?

@ayende La primera iteración está en desarrollo activo, creo que tendremos los resultados en unas semanas.

@swaroop-sridhar

Creo que el diseño actual aborda sus escenarios en la mejor medida posible en ausencia de una compilación AOT pura. Si tiene alguna inquietud sobre el diseño, no dude en mencionarla.

Ejecutar: HolaMundo.exe

La aplicación incluida y los archivos de configuración se procesan directamente desde el paquete.
Los 216 archivos restantes se extraerán al disco al inicio.

¿Qué sucede si necesito ejecutar desde fs de solo lectura, esto es común para IoT, o si el exe se ejecuta dentro de un contenedor ro? ¿Por qué no existe la opción de ejecutarlo directamente desde el exe también?

@etherealjoy El ejemplo que se muestra en esta sección es el resultado esperado para HelloWorld independiente a partir de la Etapa 2 del desarrollo de esta función (como se menciona en esta sección ). En esta etapa, las únicas aplicaciones que pueden ejecutarse directamente desde el EXE son las aplicaciones administradas puramente que dependen del marco.

Si estamos en la Etapa 4 o la Etapa 5 , la aplicación independiente anterior puede ejecutarse directamente desde el paquete.

¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)

Básicamente todo lo anterior. Utilidades de consola, WPF, asp.net, juegos

¿Tu aplicación incluye código C++/nativo (no .NET)?

Si. Sqlite es un buen ejemplo.

¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?

Probablemente no.

¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?

Si.

¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?

net.core ya es un poco demasiado lento. Pero un aumento de un par de segundos es aceptable. 5 segundos, definitivamente no.

¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?

No importa hoy en día

¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?

Hasta 5 minutos se siente aceptable. Las compilaciones de lanzamiento de 15 a 20 minutos para UWP están volviendo locos a todos.

¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?

Por supuesto.

Gracias @mjr27

La implementación de la etapa 1 ahora está completa y está disponible a partir de 3.0.100-preview5-011568 .

Las aplicaciones se pueden publicar en un solo archivo configurando la propiedad PublishSingleFile en true como se explica aquí .

En esta versión, todos los archivos incrustados se extraen al disco en la primera ejecución y se reutilizan en ejecuciones posteriores, como se explica aquí .

Rendimiento de compilación
No hay una diferencia significativa en el tiempo si los archivos se escriben en el directorio de publicación como archivos individuales o como un solo archivo.

Tamaño de archivo e inicio
La siguiente tabla muestra el rendimiento de un par de aplicaciones creadas como un solo archivo.

  • Consola: Una aplicación de hola mundo. El tiempo informado es el tiempo para ejecutar la aplicación, medido a través de tics de reloj.
  • Aplicación WPF: aplicación de catálogo msix . El tiempo informado es el tiempo de inicio a la pantalla inicial, medido a través de un cronómetro.
  • Fw: compilaciones dependientes del marco
  • Auto: compilaciones independientes.
    Todas las ejecuciones se cronometraron cuando las comprobaciones antivirus están desactivadas para minimizar el impacto de factores externos.

Medida | Consola Fw | Consola propia | WPF Fw | WPF propio
-- | -- | -- | -- | --
Tamaño de archivo (MB) | 0.32 | 66,5 | 20.69 | 118.9
Funcionamiento normal (seg) | 0.123 | 0.127 | 3.32 | 3.24
Primera ejecución de un solo exe (seg) | 0.127 | 0,565 | 3.67 | 4.14
Ejecuciones posteriores de un solo exe (seg) | 0.124 | 0.128 | 3.30 | 3.29

Seguiré actualizando los números a medida que la implementación avanza en las etapas posteriores de desarrollo.

Noticias excelentes. Gracias

¿Se terminarán todas las etapas mencionadas en el documento de preparación para 3.0 RTM? ¿O tendremos que esperar a la publicación 3.0 para que se implementen?

Como se menciona aquí , se espera que .net core 3.0 implemente la Etapa 2 de modo que las aplicaciones msil puras dependientes del marco puedan ejecutarse directamente desde el paquete. Las etapas restantes se considerarán para futuras versiones.

Como se menciona aquí , se espera que .net core 3.0 implemente la Etapa 2 de modo que las aplicaciones msil puras dependientes del marco puedan ejecutarse directamente desde el paquete. Las etapas restantes se considerarán para futuras versiones.

:( esperaba que pudiera llegar a RTM.

@cup Pensé que podrías hacerlo con dotnet publish -o out /p:PublishSingleFile=true /p:RuntimeIdentifier=win-x64 . Acabo de probar creando una aplicación de consola estándar y ejecutando ese comando. Funcionó con éxito.

Puede ir aún más lejos al agrupar en el archivo .pdb con dotnet publish -o out /p:PublishSingleFile=true /p:RuntimeIdentifier=win-x64 /p:IncludeSymbolsInSingleFile=true

Gracias @seesharprun por las notas detalladas. Sí, @cup , el método recomendado para la publicación de un solo archivo desde la línea de comandos es establecer la propiedad PublishSingleFile desde la línea de comandos.

@etherealjoy, los repositorios de tiempo de ejecución de coreclr se bloquearán en su mayoría en el trabajo de funciones wrt en aproximadamente un mes. No creo que haya suficiente tiempo para todas las etapas. Espero que las etapas subsiguientes lleguen en la próxima versión.

Conseguí que esto funcionara hoy, pero parece que alterar el directorio base de extracción no funciona. Según esta sección . Debería poder agregar un cambio de aplicación en runtimeconfig llamado ExtractBaseDir para modificar la ubicación en la que se extrae la aplicación.

Tengo un runtimeconfig.template.json que se ve así

{
    "configProperties" : {
        "ExtractBaseDir": "C:\\"
    },
    "ExtractBaseDir": "C:\\"   
}

El app.runtimeconfig.json producido se ve así:

{
  "runtimeOptions": {
    "configProperties": {
      "ExtractBaseDir": "C:\\"
    },
    "ExtractBaseDir": "C:\\"
  }
}

Cuando se ejecuta a través del exe producido, aunque todavía se extrae a la carpeta tmp.

Supongo que esta función simplemente no está lista en Preview5, pero quería asegurarme, ya que no está claro dónde se supone que debe ir "ExtractBaseDir" en runtimeconfig.json y no hay ejemplos.

@igloo15 Gracias por mencionar esto.

En la vista previa actual, solo está habilitada la variable de entorno DOTNET_BUNDLE_EXTRACT_BASE_DIR . Esto se debe a que en la etapa actual de implementación , todos los archivos, incluido runtimeconfig.json , se extraen al disco antes de procesarlos.

Estoy trabajando para agregar soporte para ExtractBaseDir en la próxima vista previa.

¿Hay alguna guía sobre cómo hacer que esto funcione con proyectos ASP.NET Core? ¿Sería el enfoque recomendado usar la reflexión para encontrar desde dónde se cargan mis tipos de sistema y configurar mi IHostingEnvironment ContentRootPath y WebRootPath en relación con ese directorio?

@keithwill Puede usar AppContext.BaseDirectory para obtener la ubicación donde la aplicación.dll y todos los demás archivos se extraen al disco. Entonces, puede usar esto como ContentRootPath .

@igloo15 : Tengo curiosidad si pudiera compartir cuál es su escenario al usar esta opción.

  • ¿Está tratando de usarlo para un escenario de depuración o implementación de producción?
  • ¿Sería suficiente la variable de entorno en este caso, o necesita la configuración runtimeconfig.json ?

También tengo curiosidad por saber de otros desarrolladores, si hay casos de uso específicos para esta configuración.

@swaroop-sridhar

Tengo una situación bastante extraña. Mi software se almacena en un recurso compartido de red y luego el recurso compartido de red se vincula a una máquina virtual aleatoria de Windows y se ejecuta directamente desde el recurso compartido de red. La máquina virtual de Windows que se activa para ejecutar el software desde el recurso compartido de red no puede tener nada modificado o cambiado. Los registros, los archivos de configuración, etc., deben crearse en el recurso compartido de red.

Curiosamente, esta configuración permite que el sistema en general distribuya varias piezas de software en una carpeta y luego clone esa estructura de carpetas para diferentes configuraciones/versiones. Luego, cuando una versión específica tiene que ejecutarse, el software de administración activa vms y asigna unidades en el vms a la versión específica del recurso compartido de red y ejecuta el software.

1.) Es un escenario de implementación de producción
2.) Las variables ambientales serían difíciles ya que la computadora que ejecuta el software es constantemente diferente y se destruye/rehace

@cup Realmente no estoy de acuerdo con que este tema se trate de implementar el documento de diseño y el documento de diseño dice específicamente que ExtractBaseDir debería funcionar para esta función.

Si este problema no se trata de implementar este documento de diseño, ¿de qué se trata este problema?

Gracias por la explicación @igloo15.

Pregunto sobre la opción de configuración, porque hay un costo para analizar los archivos de configuración al principio del código AppHost. Actualmente, AppHost no se vincula con el código para analizar los archivos json (en su lugar, son utilizados por hostfxr/hostpolicy). Agregar esta característica en la actualidad haría que AppHost fuera un poco más grande/complejo. Sin embargo, una vez que la implementación pasa a otras etapas (en las que todo el código de tiempo de ejecución y el alojamiento están vinculados entre sí), esto ya no es un problema.

@igloo15 el documento de diseño es una parte importante, pero el núcleo de este problema es la función en sí. ExtractBaseDir es un parámetro opcional y preferiría ver que la función principal se pase a la versión "actual" en lugar de atascarse con parámetros opcionales.

@cup , hice la pregunta aquí porque llamé la atención de los desarrolladores interesados ​​en este hilo.
Si bien no creo que la pregunta esté fuera de tema, entiendo su preocupación sobre la longitud de este hilo. Crearé un problema vinculado la próxima vez. Gracias.

@cup @swaroop-sridhar

Un par de cosas que diría primero es que esta característica solo importa para la etapa 1 del documento de etapa. Todas las demás etapas 2 - 5 se tratan de ejecutar los dlls desde dentro del paquete y no extraerlos. Por lo tanto, una configuración para determinar la ubicación del directorio base de extracción no es realmente útil para las etapas 2-5. Como NetCore 3.0 tiene la intención de desarrollar la etapa 1, espero que esta función esté allí, ya que es la única vez que sería útil.

En segundo lugar, ¿cómo diferenciamos este método de otros métodos como dotnet-wrap? Para mí, la principal ventaja de este método es que estamos integrando este proceso en la cadena de compilación más cerca de cuando se compila el código. Además, esta es una función que está orientada a .NET y, por lo tanto, comprende los matices de las aplicaciones .NET Core, como sus configuraciones, el proceso de compilación, etc. Como tal, espero que nos centremos en las funciones que diferencian esta herramienta de otras herramientas que son no está orientado específicamente al núcleo neto. Estas serían características como configurar la ubicación de extracción que dotnet-wrap no puede hacer.

En cuanto a cómo se implementa, no estoy seguro, pero creo que, en lugar de leer el ExtractBaseDir de la configuración en el tiempo de ejecución, ¿no podríamos incorporar eso en el paquete exe en el momento de la compilación? No he visto el código que hace que este proceso de paquete funcione, pero en mi opinión está generando/construyendo un exe nativo con todos los dlls, etc. dentro de él. ¿No podríamos, durante la generación/construcción de exe, leer el archivo runtimeconfig de las aplicaciones incluidas, sacar el ExtractBaseDir y configurarlo como una propiedad en el paquete nativo exe?

Entonces, no lee una configuración de tiempo de ejecución incrustada en tiempo de ejecución, sino que aprovecha una propiedad internamente para determinar la ubicación de extracción. Eso debería ser potencialmente mucho más rápido.

@igloo15 : Extraer contenido del paquete al disco puede ser útil para ciertas aplicaciones más allá de la Etapa 2.
Por ejemplo, si la aplicación tiene archivos binarios nativos personalizados en el paquete, entonces deberán extraerse hasta la Etapa 5. Es posible que la aplicación desee agrupar archivos de contenido de tipo desconocido para extraerlos en archivos en tiempo de ejecución.

Estoy de acuerdo en que la utilidad de esta configuración se reduce a medida que avanzamos en etapas posteriores de desarrollo. Sin embargo, una vez que agreguemos la opción, es probable que tengamos que mantenerla en todas las versiones posteriores por motivos de compatibilidad. Por lo tanto, necesita una cuidadosa consideración ahora.

Estoy de acuerdo en que hacer que la ubicación de extracción sea una configuración de tiempo de compilación (por ejemplo, msbuild-property) en lugar de una opción de configuración de tiempo de ejecución es una implementación de wrt más fácil y eficiente. Gracias.

Hola, tengo un par de preguntas sobre este tema:

Me gustaría usar la función de distribución de un solo archivo para empaquetar aplicaciones de .NET Framework 4.7.2 (por ejemplo) en un solo ejecutable. ¿Es esa la intención de esta función o solo está destinada a admitir aplicaciones .NET Core?

Mi segunda pregunta está relacionada con cómo se hace el empaque. Cuando se crea el ejecutable, ¿el tiempo de ejecución de los marcos de destino se incluirá en el ejecutable? ¿O debe estar preinstalado en la máquina de destino que ejecutará la aplicación?

@gaviriar No creo que admita aplicaciones .NET Framework. Y sí, puede agrupar el tiempo de ejecución de .NET Core en un ejecutable (lo que se denomina publicación "autónoma").

@ tomrus88 gracias por la respuesta. Es una verdadera lástima con respecto a las aplicaciones de .NET Framework. ¿Hay algún método que recomendaría que pudiera usarse para agrupar el tiempo de ejecución de .NET Framework en un ejecutable?

Veo una lista de herramientas en la sección de trabajo relacionado del documento. ¿Hay alguno en particular que pueda recomendarse para el caso de uso propuesto anteriormente?

@gaviriar .NET Framework es parte del sistema operativo Windows. No existe una forma compatible de empaquetarlo en un ejecutable.

@gaviriar La necesidad de agrupar el tiempo de ejecución es una de las principales razones para cambiar a .NET Core.

@jnm2 y @jkotas gracias por la aclaración, novato aquí en el mundo .NET. Acepto que me encantaría cambiar a .NET Core. Sin embargo, me enfrento a un caso en el que tengo que interactuar con una biblioteca heredada que apunta a .NET Framework. En tal caso, entiendo que no puedo cambiar mi aplicación a .NET Core si necesito interactuar con esta biblioteca. ¿O existe un enfoque alternativo para que mi aplicación sea .NET Core pero aún pueda interactuar con la biblioteca heredada de .NET Framework?

Depende de la biblioteca. Muchas bibliotecas que apuntan a .NET Framework también funcionan bien en .NET Core. ¿Has intentado usar la biblioteca en .NET Core? Si has comprobado que no funciona, no puedes cambiar hasta que tengas una solución para ello.

De hecho, lo probé, pero esto no funciona ya que estamos hablando de bibliotecas que son específicas de Windows. Supongo que no tengo otra opción que seguir apuntando a .NET Framework y perderme la diversión de .NET Core como dices :/

@gaviriar Esto está fuera de tema, pero ¿ha probado el paquete NuGet de compatibilidad de Windows? Proporciona apis de Windows para .NET Core para el propósito exacto que está describiendo Microsoft.Windows.Compatibility

@gaviriar : Algunas aclaraciones más:

Cuando se crea el ejecutable, ¿el tiempo de ejecución de los marcos de destino se incluirá en el ejecutable? ¿O debe estar preinstalado en la máquina de destino que ejecutará la aplicación?

Esto depende de la construcción. Tanto las aplicaciones dependientes del marco (el tiempo de ejecución está instalado en el destino) como las independientes (el tiempo de ejecución está empaquetado con la aplicación) se pueden publicar como un solo archivo, pero solo las aplicaciones .net core 3.0.

Veo una lista de herramientas en la sección de trabajo relacionado del documento. ¿Hay alguno en particular que pueda recomendarse para el caso de uso propuesto anteriormente?

Para .net framework, la mejor solución que puedo sugerir es que la aplicación maneje la extracción de archivos por sí misma. Por ejemplo: incruste las dependencias como recursos administrados en el archivo binario de la aplicación y luego extraiga explícitamente los recursos al inicio. También puede usar la biblioteca de paquetes para la agrupación y la extracción (porque la biblioteca está construida según el estándar neto), pero usar recursos administrados es una mejor solución.

@ igloo15 y @ swaroop-sridhar Agradezco estas entradas considerando que están fuera de tema. Aunque espero que alguien más encuentre útil esta discusión cuando lea algún día.

Evaluaré las opciones que ha compartido conmigo y le haré saber cuál resulta ser el mejor enfoque para mi caso de uso.

¡Gracias!

¡Actualización rápida!

He probado esta sencilla aplicación Hello World . Puedo construir con éxito un solo archivo ejecutable. Sin embargo, como puede ver en la configuración del proyecto, está destinado a ser autónomo. Pero cuando trato de ejecutar este ejecutable en una instalación nueva de Windows 7 sin ningún tiempo de ejecución de .NET core instalado, veo el siguiente error:

Failed to load the DLL from [C:\Users\vagrant\AppData\Local\Temp\.net\HelloWorld
\muasjfkf.kyn\hostfxr.dll], HRESULT: 0x80070057
The library hostfxr.dll was found, but loading it from C:\Users\vagrant\AppData\
Local\Temp\.net\HelloWorld\muasjfkf.kyn\hostfxr.dll failed
  - Installing .NET Core prerequisites might help resolve this problem.
     https://go.microsoft.com/fwlink/?linkid=798306

Lo que puedo ver es que la publicación de la aplicación como dotnet publish /p:PublishSingleFile=true o /p:PublishSingleFile=false no cambia el tamaño del ejecutable. ¿Es este el comportamiento esperado?

Pasos para reproducir

  1. Publicar el proyecto para generar los HelloWorld.exe

  2. Copie el ejecutable a una instalación de Windows 7 sin ningún tiempo de ejecución de .NET Core instalado

  3. Ejecute el HelloWorld.exe

@gaviriar Probé el ejemplo que publicaste y me funcionó bien.
Es decir, creó un único exe autónomo para HelloWorld que funciona bien.

Lo que puedo ver es que la creación de la publicación de la aplicación como publicación dotnet /p:PublishSingleFile=true o /p:PublishSingleFile=false no cambia el tamaño del ejecutable. ¿Es este el comportamiento esperado?

Esto definitivamente no se espera. La aplicación de un solo archivo debe tener unos 70 MB (para la compilación de depuración indicada en su página de gitlab). De lo contrario, es un host de aplicaciones normal, que se espera que falle exactamente como se indicó anteriormente. ¿Estás publicando desde un directorio limpio?

Otra nota sobre su archivo de proyecto: tiene una de las propiedades escritas incorrectamente como IncludeSymbolsInFile en lugar de IncludeSymbolsInSingleFile . Pero esto no tiene conexión con el problema que has informado.

@gaviriar ¿cuáles son sus identificadores de tiempo de ejecución de destino? Si no lo configura correctamente, no incluirá el hostfxr.dll correcto. Es posible que hostfxr.dll requiera un redistribuible vc++ específico que no existe en su máquina con Windows 7. Puede verificar que existe el dll en la ruta dada y, si lo hace, intente cargarlo en la herramienta Dependency Walker para ver si existe un dll del que depende.

Fusión de IL: herramientas como ILMerge combinan la IL de muchos ensamblajes en uno, pero pierden la identidad del ensamblaje en el proceso. Este no es un objetivo para la característica de un solo archivo.

perder la identidad del ensamblado

Esto no es un problema.
Siempre estoy en contra de usar zip / unzip u otra solución de paquetes para la función independiente Single exe.
porque esto causará los próximos problemas.
¿Cómo reducir el tamaño del archivo exe único? ¿o por qué el archivo exe es tan grande pero es solo un hola mundo?

Siempre existe el problema, y ​​debe abordarse, ¿por qué no hacer un análisis exhaustivo?
De hecho, desde un principio debería utilizar IL-Merge de formas similares.

De hecho, la gente no está realmente tan obsesionada con un solo EXE.
exe (1) + dll (1-2) también está bien, pero no 400 dlls de montaje.
A la gente no le gustará que el código nunca se ejecute en el disco del servidor y ejecutarlo en las memorias del servidor.
la gente solo quiere reducir el costo de implementación (disco, memoria, ancho de banda, etc.)

Eliminé el hito 3.0, por lo que este problema rastrea la implementación de la función de archivo único a través de las etapas descritas en este documento , que está más allá del alcance de la versión 3.0.

@sgf , estoy de acuerdo en que se necesita trabajo para reducir el tamaño del archivo. Las oportunidades de reducción de tamaño son de dos formas, no están vinculadas específicamente a un solo exe:
1) Reducir la cantidad de contenido que necesita ser publicado. Por ejemplo:
* Use herramientas similares a ILLinker para recortar binarios innecesarios, partes de ensamblajes, etc.
Este trabajo es rastreado por separado por problemas como dotnet/coreclr#24092 y mono/linker#607
* Podemos considerar otras medidas, como tener un modo de "capacidad reducida" en el que no se admita JITting para reducir el
2) Agregue la función de compresión a la publicación de un solo archivo.

Las funciones anteriores pueden funcionar juntas para reducir el tamaño de las aplicaciones de un solo archivo (y de las que no son de un solo archivo):
Por ejemplo, para la aplicación de consola HelloWorld,
Tamaño de publicación normal = 67,4 MB
Tamaño recortado = 27 MB
Recortado, archivo único, comprimido (mediante prototipo) = 12 MB

@ swaroop-sridhar ¿Hay alguna forma de obtener la ruta de su único archivo exe dentro de su aplicación?
El uso Assembly.GetExecutingAssembly().Location generará el directorio de extracción en \AppData\Local\Temp.net.

@ chris3713 Actualmente, la mejor manera de acceder a la ubicación del exe es mediante PInvoke-ing a las API nativas. Por ejemplo: GetModuleFileNameW (Null, <buffer>, <len>)

@ chris3713 Actualmente, la mejor manera de acceder a la ubicación del exe es mediante PInvoke-ing a las API nativas. Por ejemplo: GetModuleFileNameW (Null, <buffer>, <len>)

Gracias, terminé usando Process.GetCurrentProcess().MainModule.FileName .

Funciona bien con asp .net core worker/web api como Servicio de Windows publicado con PublishSingleFile=true.

Cuando registro el servicio y lo ejecuto a través sc create testwk binPath="[...]/MyAspNetCoreWorker.exe" luego sc start testwk tengo este mensaje de éxito:

[...]\bin\publish\x64>sc start testwk

SERVICE_NAME: testwk
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 5060
        FLAGS              :

[...]\bin\publish\x64>sc stop testwk

SERVICE_NAME: testwk
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 3  STOP_PENDING
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

No puedo esperar a ver la Etapa 2 con la ejecución en paquete 😀
Por cierto, ¿se seguirá planeando que la Etapa 2 sea parte de .Net Core 3.0?

Gracias por su trabajo, el servicio de publicación en .net core ahora es realmente simple 👍

CoreRT: ( 2.5mb )

image

image

Sin pirateo zip , sin costos ocultos , el motor contiene solo lo que se necesita, y las funciones no utilizadas se deshabilitan usando csproj config (reflexión)

Esto es lo que necesita dotnet, compite con GO e incluso lo supera tanto en tamaño como en rendimiento.

Para cualquier persona interesada, consulte el repositorio:

https://github.com/dotnet/coret

Hay muestras para MonoGame:

https://github.com/dotnet/corert/tree/master/samples/MonoGame

Ninguna de las soluciones propuestas puede lograr este resultado, CoreRT es realmente el mejor, MS está cometiendo un gran error al no enfocarse en él

He probado esta función en macOS con dotnet-sdk-3.0.100-preview8-013656-osx-x64.tar.gz . Si cambiamos la configuración, de Depurar a Liberar o viceversa y compilar de nuevo, se agregan 10 MB al tamaño del ejecutable. Volver a compilar con la configuración anterior no recupera este aumento de tamaño a menos que eliminemos el directorio bin .

mkdir /tmp/dotnet-preview8
curl -s https://download.visualstudio.microsoft.com/download/pr/a974d0a6-d03a-41c1-9dfd-f5884655fd33/cf9d659401cca08c3c55374b3cb8b629/dotnet-sdk-3.0.100-preview8-013656-osx-x64.tar.gz | tar -xvz -C /tmp/dotnet-preview8
export PATH=/tmp/dotnet-preview8:$PATH

dotnet new console -o /tmp/myApp
pushd /tmp/myApp

# publish with Debug
dotnet publish /p:PublishSingleFile=true,RuntimeIdentifier=osx-x64,Configuration=Debug -o bin/a/b/c/d

bin/a/b/c/d/myApp
# outputs: Hello World!

du -sh bin/a/b/c/d
# outputs  70M  bin/a/b/c/d

# publish with Release
dotnet publish /p:PublishSingleFile=true,RuntimeIdentifier=osx-x64,Configuration=Release -o bin/a/b/c/d

du -sh bin/a/b/c/d
# outputs:  80M bin/a/b/c/d

# publish with Debug again
dotnet publish /p:PublishSingleFile=true,RuntimeIdentifier=osx-x64,Configuration=Debug -o bin/a/b/c/d
# still outputs:  80M   bin/a/b/c/d

Incluso sin cambiar la configuración de compilación, si invocamos Reconstruir objetivo posteriormente ( /t:Rebuild ) después de la compilación inicial, el tamaño de salida aumenta.

Gracias @ am11 por echar un vistazo. Publicar reteniendo binarios antiguos es un problema conocido (cc @nguerrera).

Desde la vista previa 8 de .Net Core 3, no puedo iniciar mi aplicación publicada de un solo archivo.
En el visor de eventos tengo este error:

image

Estoy en Windows Server 2019

Editar: este error ocurrió después de actualizar .Net Core SDK Preview 7 a .Net Core SDK Preview 8. Después de reiniciar el servidor, puedo iniciar mi aplicación correctamente nuevamente.

@Safirion hicimos un cambio en el formato interno subyacente en torno a estas vistas previas. Es posible que haya atravesado la salida de una vista previa y la haya construido con otra. No hay descansos entre Preview 8 y 9.

En Linux, la ruta de extracción predeterminada parece ser /var/tmp/.net. En AWS lambda, la ruta /var no se puede escribir, por lo que falla la creación de esa carpeta. Para salir de la caja de ejecución sin configurar DOTNET_BUNDLE_EXTRACT_BASE_DIR, propongo cambiar esto a /tmp/.net. O tal vez debería haber múltiples intentos en ubicaciones comunes (/var/tmp, /tmp, mismo directorio que binario, etc.)

@stevemk14ebr gracias por informar ese problema. ¿Puede presentar una nueva edición para rastrear ese trabajo? https://github.com/dotnet/core-setup

@jeffschwMSFT Se arrojó el mismo error con el paso de .Net Core P9 a RC1.

Description: A .NET Core application failed.
Application: Setup.exe
Path: C:\Users\Administrateur\Desktop\Setup.exe
Message: Failure processing application bundle.
Failed to determine location for extracting embedded files
A fatal error was encountered. Could not extract contents of the bundle

@Safirion gracias por informar este problema. ¿Puedes crear un número separado para reproducir esto? https://github.com/dotnet/core-setup
cc @swaroop-sridhar

@Safirion , ¿puede enviar instrucciones de reproducción? ¿Es esta falla determinista?
Presente un problema en el repositorio de configuración central, como @jeffschwMSFT sugirió anteriormente.

Miré esto y esto solo sucedería si la aplicación se ejecuta en un entorno donde no se puede acceder al directorio temporal. Por ejemplo si hago esto:

set "TMP=wrong_path"
myapp.exe

falla con

Failure processing application bundle.
Failed to determine location for extracting embedded files
A fatal error was encountered. Could not extract contents of the bundle

Tenga en cuenta que el paquete busca un directorio temporal mediante la API de win32 GetTempPath . Que utiliza el env. variable TMP , seguida de TEMP y así sucesivamente. Si el primero con valor contiene una ruta no válida, fallaría así.

Puede solucionar esto asegurándose de que la ruta temporal esté configurada correctamente, o puede configurar explícitamente DOTNET_BUNDLE_EXTRACT_BASE_DIR en una ubicación donde desea que se realice la extracción.

@Safirion , ¿puede enviar instrucciones de reproducción? ¿Es esta falla determinista?
Presente un problema en el repositorio de configuración central, como @jeffschwMSFT sugirió anteriormente.

No puedo reproducir este problema después de actualizar .Net Core a RC1 y reiniciar mi servidor. (He intentado desinstalar RC1 e instalar Preview 9 nuevamente para actualizar nuevamente a RC1 pero mi aplicación se inicia bien esta vez)

Este error ha ocurrido con el paso de SDK 3.0 P7 a SDK 3.0 P8 y SDK 3.0 P9 a SDK 3.0 RC1.
Y en los dos casos, un simple reinicio del servidor soluciona el problema.

Utilizo un servicio de Windows .Net Core (trabajador que usa la carpeta C:\Windows\Temp\.net para extraer desde que lo inicia el sistema) y una aplicación .Net Core WPF (lanzamiento mediante el script de sesión de inicio del usuario) cuando actualicé a RC1. Tal vez este error se deba a que .Net Core Worker se ejecuta durante la instalación de .Net Core SDK, no lo sé...

Tenga en cuenta que instalo SDK y no el tiempo de ejecución porque tengo que implementar el tiempo de ejecución 3 .Core (asp.net core, desktop .net core y core) al mismo tiempo y https://dot.net no nos da un "Tiempo de ejecución completo instalador" (ni siquiera encontré el instalador de Desktop Runtime, así que no hay otra opción)...

Actualización: no importa, encontré la documentación .

¡Hola, gracias por su arduo trabajo!

¿Cómo se supone que se distribuyen los archivos de configuración (App.config, por ejemplo)? Acabo de crear una aplicación de consola en RHEL 7.6 con la secuencia de comandos exacta:

dotnet restore -r win-x64 --configfile Nuget.config
dotnet build Solution.sln --no-restore -c Release -r win-x64
dotnet publish --no-build --self-contained -c Release -r win-x64 /p:PublishSingleFile=true -o ./publish ./SomeDir/SomeProj.csproj

donde SomeProj.csproj tiene <PublishTrimmed>true</PublishTrimmed> habilitado, y obtuvo 2 archivos como resultado: SomeProj.exe y SomeProj.pdb , pero no SomeProj.config

@catlion para tener el comportamiento predeterminado de los archivos *.config, deben excluirse del paquete. De forma predeterminada, todos los archivos que no son pdb se incluyen en el paquete.
Lo siguiente excluirá la configuración del archivo único:

<ItemGroup>
    <Content Update="*.config">
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </Content>
  </ItemGroup>

https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#build -system-interface

@morganbr

¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)

Aplicaciones sin cabeza y WPF para Windows

¿Tu aplicación incluye código C++/nativo (no .NET)?

Sí, hacemos P/Invoke a una variedad de dlls nativos, algunos elementos de terceros sobre los que no tenemos control, algunos internos de otros equipos.

¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?

Sí, pero usamos CompilerServices para compilarlos desde la fuente.

¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?

¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?

Sí, nuestra aplicación generalmente se deja abierta durante largos períodos de tiempo.

¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?

Sí, podemos esperar varios minutos.

¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?

Gracias @john-cullen

Vinculación de algunos PR a la rama de un solo archivo ejecutable para una implementación prototipo de ejecución de aplicaciones de un solo archivo sin extracción ( Etapa 4 ).

https://github.com/dotnet/coreclr/pull/26197
https://github.com/dotnet/coreclr/pull/26504
https://github.com/dotnet/coreclr/pull/26697
https://github.com/dotnet/coreclr/pull/26904

Permíteme también proporcionar algunas respuestas para @morganbr :) No sé si todavía las lees :)

  1. ¿Con qué tipo de aplicación es probable que la uses? (por ejemplo, WPF en Windows? ¿ASP.NET en un contenedor Linux Docker? ¿Algo más?)

Aventuras de texto (aplicaciones de consola) para ejecutar en diferentes plataformas (Linux, MacOS, Windows)

  1. ¿Tu aplicación incluye código C++/nativo (no .NET)?

No.

  1. ¿Su aplicación cargaría complementos u otros archivos DLL externos que no incluyó originalmente en la compilación de su aplicación?

Actualmente no, pero sería genial a largo plazo admitir ciertos escenarios.

  1. ¿Está dispuesto a reconstruir y redistribuir su aplicación para incorporar correcciones de seguridad?

Si.

  1. ¿Lo usarías si tu aplicación comenzara 200-500 ms más lentamente? ¿Qué hay de 5 segundos?

Si.
(Sería genial proporcionar alguna salida de texto o un cuadro de mensaje para notificar al usuario que algo está sucediendo)

  1. ¿Cuál es el tamaño más grande que consideraría aceptable para su aplicación? 5 MB? 10? 20? 50? 75? 100?

10-20 MB

  1. ¿Aceptaría un tiempo de compilación de versión más prolongado para optimizar el tamaño o el tiempo de inicio? ¿Cuánto es lo más largo que aceptarías? ¿15 segundos? ¿30 segundos? ¿1 minuto? ¿5 minutos?

1+ minutos está bien.

  1. ¿Estaría dispuesto a hacer un trabajo adicional si redujera el tamaño de su aplicación a la mitad?

Posiblemente.

Gracias por la respuesta, @lenardg.

Este problema realiza un seguimiento del progreso en la función de distribución de un solo archivo de .NET Core 3.0.
Aquí está el documento de diseño y el plan de preparación para la función.

Esta es una característica muy útil para facilitar la implementación y reducir el tamaño.
Algunas ideas de mejora en el diseño, especialmente para implementaciones empresariales donde el entorno está estrictamente controlado a través de políticas de grupo.

  1. Condicionalmente, ¿es posible comprimir mientras se empaqueta el único ejecutable?
    es decir, agregue la lógica Wrap, por lo que no necesitamos la integración de otras herramientas.
    El comprimido producirá un exe aún más pequeño.

  2. Al iniciar el exe, expande su contenido a una carpeta temporal. Para nuestro producto, en ciertos sitios de usuarios, las máquinas cliente están estrictamente controladas y no permiten que se inicien ejecutables desde la carpeta temporal o incluso desde las ubicaciones %userprofile%.

¿Es posible especificar/controlar dónde extraer o puede ser 'extraer en el lugar' en un ".\extract" o subcarpeta similar?
Esto permite el cumplimiento de las políticas de grupo, así como la capacidad de usar la función de ejecución única.

  1. Antes de empacar, ¿es posible firmar la carpeta y luego selecciona los archivos para empacar?
    Podemos firmar el único exe, pero los archivos de extracción no están firmados y, por lo tanto, en otras ubicaciones de clientes, no permite la ejecución, a menos que los archivos binarios estén firmados.

Solo quería que supieras que vi el mismo problema que @Safirion hoy. Tengo una aplicación dotnetcore 3.0 dirigida a ubuntu y fui a ejecutarla en mi servidor Synology. No se extraía: seguía fallando con un error "Se encontró un error fatal. No se pudo extraer el contenido del paquete". Reconstruido varias veces, pero lo mismo. Después de reiniciar el host, funcionó bien nuevamente.

Sería útil entender si hay un bloqueo de archivo o algo aquí, y si hay algún momento sobre cómo depurarlo.

@RajeshAKumar dotnet /core-setup#7940

No estoy seguro de cómo ayuda ese enlace.
Solo habla de la extracción temporal, he enumerado 3 puntos arriba.

Y te di la solución para uno de ellos. no tengo idea de los otros 2

Y te di la solución para uno de ellos. no tengo idea de los otros 2

El extracto temporal no funciona para nosotros, por lo tanto, esa no es la solución. Mi solicitud fue la capacidad de controlar dónde se extrae o se puede extraer en el lugar en una subcarpeta.
Los administradores de TI en muchas de nuestras computadoras cliente no permiten ejecutar ejecutables desde carpetas temporales o desde el perfil de usuario.
Vuelva a leer la publicación https://github.com/dotnet/coreclr/issues/20287#issuecomment -542497711

@RajeshAKumar : puede configurar DOTNET_BUNDLE_EXTRACT_BASE_DIR para controlar la ruta base donde el host extrae el contenido del paquete.
Consulte más detalles aquí: https://github.com/dotnet/designs/blob/master/accepted/single-file/extract.md#extraction -ubicación

@RajeshAKumar : La compresión del archivo ejecutable único incluido es una función que se está considerando para .net 5: https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#compression

Por ahora, necesitará usar otras utilidades para comprimir el único exe generado.

@RajeshAKumar , con respecto a la firma, puede firmar todos los archivos/binarios que se publican y se agrupan en el único archivo exe. Cuando el host extrae los componentes incrustados en el disco, los archivos individuales se firmarán. También puede firmar el archivo único creado, como mencionó.

¿Eso cumple con sus requisitos?

@Webreaper Si puede reproducir el problema, ¿puede ejecutar la aplicación con COREHOST_TRACE activado (establecer la variable de entorno COREHOST_TRACE en 1 ) y compartir el registro generado? Gracias.

@swaroop-sridhar
Esta es una característica muy interesante. ¿Tiene un enlace sobre cuándo estarán disponibles las diferentes etapas en qué versión de dotnet?

@RajeshAKumar : puede configurar DOTNET_BUNDLE_EXTRACT_BASE_DIR para controlar la ruta base donde el host extrae el contenido del paquete.
Consulte más detalles aquí: https://github.com/dotnet/designs/blob/master/accepted/single-file/extract.md#extraction -ubicación

gracias swaroop-sridhar

@RajeshAKumar , con respecto a la firma, puede firmar todos los archivos/binarios que se publican y se agrupan en el único archivo exe. Cuando el host extrae los componentes incrustados en el disco, los archivos individuales se firmarán. También puede firmar el archivo único creado, como mencionó.

¿Eso cumple con sus requisitos?

Estoy tratando de descubrir cómo romper la 'compilación' y publicar partes.
Actualmente uso el siguiente comando, por lo que no me permite firmar.
Establecer publicarargs=-c Liberar /p:PublishSingleFile=True /p:PublishTrimmed=True /p:PublishReadyToRun=false
dotnet publicar -r win-x64 -o bin\Output\Win64 %publishargs%

Dado que lo anterior compila, así como los recortes y los paquetes, no estoy seguro de cómo descifrarlos.
Idealmente, para usar su enfoque, tendré que compilarlo, luego firmarlo y finalmente publicarlo.

@Webreaper Si puede reproducir el problema, ¿puede ejecutar la aplicación con COREHOST_TRACE activado (establecer la variable de entorno COREHOST_TRACE en 1 ) y compartir el registro generado? Gracias.

Gracias. Ha desaparecido ahora porque reinicié, ¡pero es útil tener esto en cuenta por si vuelve a suceder!

@RajeshAKumar deberá etiquetar la firma en un destino que se ejecuta justo antes de la agrupación.
Como está usando PublishReadyToRun y PublishTrimmed , no puede usar los objetivos estándar Afterbuild o BeforePublish .

Puede agregar un destino que se ejecuta justo antes BundlePublishDirectory y realiza la firma.

@swaroop-sridhar
Esta es una característica muy interesante. ¿Tiene un enlace sobre cuándo estarán disponibles las diferentes etapas en qué versión de dotnet?

Gracias @etherealjoy. El trabajo para archivos únicos que se ejecutan directamente desde el paquete está en progreso, apuntando a la versión .net 5 según mi mejor entendimiento.

@RajeshAKumar deberá etiquetar la firma en un destino que se ejecuta justo antes de la agrupación.
Como está usando PublishReadyToRun y PublishTrimmed , no puede usar los objetivos estándar Afterbuild o BeforePublish .

Puede agregar un destino que se ejecuta justo antes BundlePublishDirectory y realiza la firma.

Gracias.
El enlace que proporcionó parece tareas de MS Build.
¿Cómo creo un controlador para "BundlePublishDirectory"? ¿Es esto en Studio/Project props/Build Events o tengo que crear algo desde cero?

@RajeshAKumar en este caso, necesitará algo más detallado que los eventos previos a la compilación posteriores a la compilación.
Entonces, creo que deberías editar el archivo del proyecto y agregar algo como:

<Target Name="Sign" BeforeTargets="BundlePublishDirectory">
    ... 
</Target>

¿Cuál es el comportamiento esperado del comando dotnet pack con esto? Digamos que tenemos un artefacto de un solo archivo ejecutable en el repositorio nuget local. Si trato de instalarlo con chocolatey, intenta restaurar todas las dependencias nuget enumeradas en el archivo del proyecto. Lo cual se esperaba anteriormente, pero tengo dudas si este comportamiento es correcto para SFD.

¿Es posible agregar alguna barra de progreso o indicador de carga durante la extracción de la aplicación WPF independiente de un solo archivo? Puede llevar algún tiempo sin que suceda nada.
Una aplicación WPF básica e independiente requiere más de 80 Mo y la extracción puede tardar más de 5 segundos. No es muy fácil de usar y recibí quejas de mis usuarios finales.

Editar: ¿Alguna forma de limpiar la versión anterior automáticamente en el lanzamiento?

@Safirion No puedo ver cómo eso podría estar dentro del alcance de esta función. Si lo necesita, sería mejor que creara su propia aplicación pequeña que muestre una pantalla de bienvenida e inicie la aplicación real, y luego haga que la aplicación real detenga el programa de pantalla de bienvenida cuando se inicie.

@ProfessionalNihilist Creo que no entiendes mi punto.
Una aplicación WPF vacía autónoma usa 80 meses de almacenamiento en disco cuando se compila. No puede tener una aplicación WPF más pequeña que 80 meses sin compilarla como una aplicación dependiente del marco 😉
El problema es el tiempo de extracción del marco incluido antes de que la aplicación pueda iniciarse. Por lo tanto, debe hacerlo .Net Core y está totalmente relacionado con esta función.

¿Quizás agregar la capacidad de tener un png que se mostraría mientras se descomprime la aplicación?

@Safirion @ayende la falta de "comentarios de la interfaz de usuario" durante el inicio se rastrea aquí: https://github.com/dotnet/core-setup/issues/7250

¿Cuál es el comportamiento esperado del comando dotnet pack con esto? Digamos que tenemos un artefacto de un solo archivo ejecutable en el repositorio nuget local. Si trato de instalarlo con chocolatey, intenta restaurar todas las dependencias nuget enumeradas en el archivo del proyecto. Lo cual se esperaba anteriormente, pero tengo dudas si este comportamiento es correcto para SFD.

@catlion la propiedad PublishSingleFile solo es compatible con el comando dotnet publish . Por lo tanto, no tiene impacto en dotnet pack . ¿Hay alguna motivación para usar tanto el archivo único como el empaquetado?

Editar: ¿Alguna forma de limpiar la versión anterior automáticamente en el lanzamiento?

@Safirion en la versión actual, la limpieza es manual, el host no intenta eliminar los archivos extraídos, porque podrían reutilizarse potencialmente en ejecuciones futuras.

Ok, haré mi propio limpiador 😉
Gracias por su respuesta.

@cup que no tiene nada de especial en mono, es solo una compilación estándar, ahora agregue una referencia nuget y esa solución ya no es un solo archivo. Mono tiene mkbundle aunque para lograr un solo archivo

@Suchiman ¿estás seguro? Mi ejemplo anterior produce un solo archivo de 3 KB. Mientras que el tamaño mínimo de dotnet parece ser de 27 MB:

https://github.com/dotnet/coreclr/issues/24397#issuecomment-502217519

@copa

C:\Users\Robin> type .\Program.cs
using System;
class Program {
   static void Main() {
      Console.WriteLine("sunday monday");
   }
}
C:\Users\Robin> C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe .\Program.cs
Microsoft (R) Visual C# Compiler version 4.8.3752.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.

This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, which is no longer the latest version. For compilers that support newer versions of the C# programming language, see http://go.microsoft.com/fwlink/?LinkID=533240

C:\Users\Robin> .\Program.exe
sunday monday
C:\Users\Robin> dir .\Program.exe


    Verzeichnis: C:\Users\Robin


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       10.11.2019     18:36           3584 Program.exe

@Suchiman ¿estás seguro? Mi ejemplo anterior produce un solo archivo de 3 KB. Mientras que el tamaño mínimo de dotnet parece ser de 27 MB:

#24397 (comentario)

Su archivo 3k solo funciona porque mono ya está instalado. El objetivo de la distribución de un solo archivo de dotnetcore es que no necesita el clr instalado, es un único exe independiente que incluye el tiempo de ejecución.

@Webreaper en realidad creo que solo usó mcs de mono para compilar, ya que no escribió mono sun-mon.exe , probablemente se ejecutó en .NET Framework.

Pero .NET Core también es compatible con el entorno de ejecución preinstalado, también conocido como implementación dependiente del marco. Sin embargo, todavía no es una implementación de un solo archivo en ese caso, ya que hay algunos archivos adicionales para .NET Core, como .deps.json y .runtimeconfig.json

@ chris3713 Actualmente, la mejor manera de acceder a la ubicación del exe es mediante PInvoke-ing a las API nativas. Por ejemplo: GetModuleFileNameW (Null, <buffer>, <len>)

Parece que Environment.CurrentDirectory es una mejor solución, aunque aún no he probado ambos enfoques en algo que no sea Windows.

EDITAR: No. Esa ruta está sujeta a cambios en diferentes puntos de entrada en la aplicación. No es bueno.

En una nota ligeramente relacionada, encontré esta regresión en la publicación de un solo archivo de las aplicaciones Blazor en la última vista previa de VS para Mac: https://github.com/aspnet/AspNetCore/issues/17079 - Lo informé en AspNeCore/Blazor, pero puede ser que esto sea más relevante para el grupo coreclr, no estoy seguro. ¡Lo dejaré para que ustedes se muevan!

@Suchiman cuidado, ese compilador tiene problemas:

https://github.com/dotnet/roslyn/issues/39856

@cup excepto que al usar la ruta del archivo que he nombrado, está usando el antiguo compilador C # 5 escrito en C ++, que no es roslyn y probablemente cerrarán ese problema por ese motivo. Pero Roslyn puede hacer lo mismo, solo que por un camino diferente...

En una nota ligeramente relacionada, encontré esta regresión en la publicación de un solo archivo de las aplicaciones Blazor en la vista previa más reciente de VS para Mac: aspnet/AspNetCore#17079 . Lo informé en AspNeCore/Blazor, pero puede ser que esto es más relevante para el grupo coreclr - no estoy seguro. ¡Lo dejaré para que ustedes se muevan!

@Webreaper Gracias por informar el problema, que parece un problema de ASP.net con respecto a los activos estáticos. Entonces, ese es el lugar correcto para archivarlo.

* Mover publicación de otro número a aquí.

@swaroop-sridhar,

Los tiempos de inicio de las aplicaciones DotNet Core Single File WPF son mucho más lentos que los de la aplicación WPF ILMerge-ed original creada en .net 4.7. ¿Es esto de esperar o mejorará en el futuro?

Las compilaciones provienen de mi ImageOptimizer: https://github.com/devedse/DeveImageOptimizerWPF/releases

| Tipo | Tiempo estimado de la primera puesta en marcha | Segundo tiempo estimado de puesta en marcha | Tamaño | Enlace de descarga |
| -- | -- | -- | -- | -- |
| .NET 4.7.0 + ILMerge | ~3 seg | ~1 segundo | 39.3mb | ENLACE |
| dotnet publique -r win-x64 -c Release --self-contained=false /p:PublishSingleFile=true | ~10 seg | ~3 seg | 49mb | |
| dotnet publicar -r win-x64 -c Liberar /p:PublishSingleFile=true | ~19 seg | ~2 seg | 201mb | |
| dotnet publique -r win-x64 -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true | ~15 seg | ~3 seg | 136mb | ENLACE |
| dotnet publicar -r win-x64 -c Lanzamiento | ~2,5 segundos | ~1,5 segundos | 223kb para exe (+400mb en dlls) | |

@devedse , para asegurarse, ¿es el "segundo inicio" el promedio de varias ejecuciones (aparte de la primera)?
Tengo curiosidad, pero me falta una explicación de por qué la ejecución /p:PublishSingleFile=true /p:PublishTrimmed=true debería ser más lenta que la ejecución de ` /p:PublishSingleFile=true .

Entonces, antes de investigar, quiero asegurarme de que los números en el "segundo inicio" sean números estables y que la diferencia en el inicio sea reproducible.

Además, este problema se trata de complementos de un solo archivo, ¿puede mover la discusión sobre rendimiento a un nuevo problema o a dotnet/coreclr#20287? Gracias.

@swaroop-sridhar, en respuesta a su pregunta sobre si es el promedio:
Es un poco difícil para mí cronometrar esto con mucha precisión, por lo que el cronometraje se realizó contando mientras la aplicación se iniciaba y luego intentándolo varias veces para ver si había una diferencia significativa en el tiempo de inicio. Si conoce un método mejor, puede reproducirlo fácilmente creando mi solución: https://github.com/devedse/DeveImageOptimizerWPF

Mi pregunta principal se relaciona con por qué una aplicación empaquetada (archivo único) tarda más en iniciarse en comparación con un archivo .exe desagregado.

Puede que me equivoque aquí, pero tiene sentido para mí, ya que hay una sobrecarga con un solo archivo. Esencialmente, tiene una aplicación que está iniciando otra aplicación. Mientras que ILMerge se inicia directamente. ILMerge solo combinó los dll referenciados en el exe, no envolvió todo en otra capa, que es lo que se está haciendo actualmente con PublishSingleFile.

@devedse El archivo único esencialmente extrae, verifica las sumas de verificación, etc. antes de iniciar la ejecución de dotnet.
Supongo que es por eso que tomó ese tiempo.
El extracto se "almacena en caché", por lo que la próxima vez que se ejecuta, no hay sobrecarga de IO.

@RajeshAKumar , hmm, ¿realmente está extrayendo el camino a seguir en este escenario? ¿No sería mejor seguir el camino de ILMerge y fusionar las DLL en un solo paquete?

Especialmente para archivos .exe más grandes, también está induciendo el costo de espacio en disco de almacenar todos los archivos dos veces.

@devedse Todos estamos esperando las próximas etapas de esta función (Ejecutar desde el paquete), pero por ahora, es la única solución. 😉

https://github.com/dotnet/designs/blob/master/accepted/single-file/staging.md

esto es lo que obtienes por usar JIT en el escritorio, inicio lento, parece que solo Apple entendió esto

(En su mayoría repitiendo lo que ya se dijo):
Se espera que el primer inicio sea mucho más lento: extrae la aplicación en el disco, por lo que hay mucho IO. El segundo inicio y los posteriores deben ser casi idénticos a la versión de la aplicación que no es de un solo archivo. En nuestras medidas internas no vimos diferencia.

Cómo medir: utilizamos el seguimiento (ETW en Windows): hay eventos cuando se inicia el proceso y luego hay eventos de tiempo de ejecución que se pueden usar para esto; sin embargo, no es exactamente fácil.

Como mencionó @Safirion , estamos trabajando en la próxima mejora para un solo archivo, que debería ejecutar la mayor parte del código administrado directamente desde el .exe (sin extracción en el disco). Sin embargo, todavía no puedo prometer un tren de lanzamiento.

JIT: todo el marco debe precompilarse con Ready2Run (CoreFX, WPF), por lo que al inicio solo el código de la aplicación debe ser JIT. No es perfecto, pero debería marcar una gran diferencia. Teniendo en cuenta los tiempos de inicio de ~ 1-2 segundos, creo que ya lo está usando en todas las pruebas.

Gracias a todos, no estaba al tanto de los próximos pasos que están planeados. Esto lo aclara.

Se espera que el primer inicio sea mucho más lento: extrae la aplicación en el disco, por lo que hay mucho IO.

Esto nunca debería haber sucedido, haces que la experiencia del usuario sea horrible POR DISEÑO, elección horrible, así es como haces que los usuarios odien la tecnología que el desarrollador está usando para ellos.

Como mencionó @Safirion , estamos trabajando en la próxima mejora para un solo archivo, que debería ejecutar la mayor parte del código administrado directamente desde el .exe (sin extracción en el disco). Sin embargo, todavía no puedo prometer un tren de lanzamiento.

¿Por qué lanzar esto oficialmente ahora si va a cambiar pronto? debe marcarse como vista previa/experimental

en mi opinión, esto es una pérdida de tiempo y recursos, concéntrese en la compilación AOT y la sacudida de árboles, ponga todos sus recursos allí, deténgase con los hacks

@RUSshy ¿Por qué tanto odio? Si no desea el retraso de inicio cuando inicia por primera vez, no utilice la implementación de un solo archivo.

Encuentro que el inicio es significativamente menor a 10 segundos, y dado que es solo la primera vez que ejecuta, no hay problema en absoluto. Estoy implementando una aplicación web del lado del servidor, lo que significa que en la mayoría de los casos se iniciará una vez y luego se ejecutará durante días/semanas, por lo que la extracción inicial es insignificante en el esquema de las cosas, por lo que preferiría esto como un provisional hasta que haya una sola imagen compilada, porque hace que la implementación sea mucho más fácil que copiar cientos de archivos DLL en el lugar.

+1 en mi caso, tenemos una ventana acoplable de compilación que genera un solo exe y una ventana acoplable separada para ejecutar la aplicación (usando una imagen acoplable normal de Alpine sin dotnet). Después del paso de bulid, cargamos en caliente el contenedor de tiempo de ejecución una vez y docker-commit la capa. Posteriormente, no hemos observado ninguna regresión en el rendimiento en comparación con una implementación dependiente del marco. Una vez que se implemente y envíe el mecanismo de archivo de carga desde el paquete, eliminaremos el paso intermedio de carga en caliente.

@vitek-karas, ¿hay algún problema al rastrear la función "cargar activos de tiempo de ejecución del paquete"? interesados ​​en comprender qué tipo de impedimentos existen. :)

@ am11 Actualmente estamos armando el plan detallado. Puede ver el prototipo que se ha realizado en https://github.com/dotnet/coreclr/tree/single-exe. La implementación real probablemente no será muy diferente (obviamente, mejor factorización, etc., pero la idea central parece ser sólida).

@Webreaper Para las aplicaciones web, no es un problema en absoluto, pero tal vez porque ahora se recomienda .Net Core 3 para el desarrollo de WPF/WinForm, y compartir una aplicación de escritorio .exe perdida en cien .dll no es una opción, entonces yo totalmente entender la frustración relacionada con la primera etapa de esta función.
;)

Y ningún usuario espere 10 segundos (o más de 3 segundos) antes de volver a hacer clic en un exe hoy. El hecho de que no haya un indicador de carga es el segundo gran problema de esta función. Desafortunadamente, parece que el indicador de carga no formará parte de .Net Core 3.1, por lo que los usuarios deberán tener paciencia...

Los desarrolladores de escritorio realmente esperan la etapa 2, y espero que sea parte de .Net 5 porque, en realidad, el desarrollo de escritorio en .Net Core es una experiencia realmente mala para los usuarios finales.

@RUSshy ¿Por qué tanto odio? Si no desea el retraso de inicio cuando inicia por primera vez, no utilice la implementación de un solo archivo.

esto no es odio, es una retroalimentación constructiva y honesta, me importa C# y .net, uso ambos todos los días, no quiero que sea reemplazado por GO u otra cosa

hace poco:
https://old.reddit.com/r/golang/comments/e1xri3/choosing_go_at_american_express/
https://old.reddit.com/r/golang/comments/ds2z51/the_stripe_cli_is_now_disponible_and_its_write/

La retroalimentación negativa es tan útil como la retroalimentación positiva, pero si lo tomas como "odio", entonces no puedo ayudarte.

La comunidad .net es silenciosa, pasiva y sesgada, la disrupción es el único camino a seguir

.NET es objetivamente la mejor plataforma para la mayoría de las aplicaciones en estos días. Ojalá más gente se diera cuenta de eso.

Las historias de guerra que escucho de otras plataformas como Java, Go, Rust, Node,... son francamente inquietantes. Estas plataformas son asesinas de la productividad.

en mi opinión, esto es una pérdida de tiempo y recursos, concéntrese en la compilación AOT y la sacudida de árboles, ponga todos sus recursos allí, deténgase con los hacks

Estoy de acuerdo. .Net tiene un gran sistema de tipos. Demasiadas veces se elude usando la reflexión. Las herramientas deben centrarse en AOT pero también en minimizar la reflexión. https://github.com/dotnet/corert/issues/7835#issuecomment -545087715 sería un muy buen comienzo. El error de miles de millones de dólares de nulos se está mitigando ahora; lo mismo se debe hacer con la reflexión con una configuración o marcador para el código libre de reflexión (o, de lo contrario, el código compatible con el enlazador o coret).

Eliminar el reflejo sería increíble. Se podría evitar tanto sufrimiento si se prohibiera la reflexión. Mi historia de terror más reciente fue descubrir que no podía mover el código porque el marco utilizado (SDK de Service Fabric) consideró prudente vincular los bytes serializados al nombre del ensamblado de la implementación del serializador sin posibilidad de anulación.

Cualquier avance hacia el desánimo de la reflexión sería un avance.

Por cierto, estaba buscando una forma de fusionar ensamblajes para reducir el tamaño del paquete y los tiempos de carga, y permitir la optimización del programa completo. Deduzco que este problema no está realmente dirigido a eso.

Editar: Dado que esta publicación reunió algunas reacciones solo para aclarar. Creo que la metaprogramación debería ocurrir en tiempo de diseño, donde el código son los datos y está bajo mi control.

Tipos que me gusta usar para aplicar invariantes en los que puedo confiar. Los reflejos en tiempo de ejecución rompen esa confianza.

Por lo tanto, me gustaría que la reflexión en tiempo de ejecución sea reemplazada por la metaprogramación en tiempo de diseño. Donde también podría ser una superposición más poderosa con casos de uso como analizadores, soluciones rápidas y refactorización.

Etiquetado de suscriptores a esta área: @swaroop-sridhar
Notifica a danmosemsft si quieres suscribirte.

El diseño de funciones de un solo archivo se encuentra en este documento: https://github.com/dotnet/designs/blob/master/accepted/2020/single-file/design.md
Seguimiento del progreso de las aplicaciones de un solo archivo en este número: https://github.com/dotnet/runtime/issues/36590.
Gracias a todos por sus comentarios y sugerencias en este número.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

jzabroski picture jzabroski  ·  3Comentarios

jchannon picture jchannon  ·  3Comentarios

bencz picture bencz  ·  3Comentarios

nalywa picture nalywa  ·  3Comentarios

sahithreddyk picture sahithreddyk  ·  3Comentarios