Diseño y Desarrollo de un sitio web utilizando ASP.NET MVC 4, EF, Knockoutjs y Bootstrap O TRA APLICACIÓN MVC: I NTRODUCCIÓN Todos los sitios web están creciendo más rápido en estos días, y una vez que crece, es muy difícil de escribir, organizar y mantener. A medida que agregamos nuevas funcionalidades o desarrollador de un proyecto, las grandes aplicaciones web con un diseño deficiente pueden salir de control. Así que la idea de este artículo es el de diseñar una arquitectura web que debe ser simple, fácilmente comprensible por cualquier diseñador web (principiante a intermedio) y los motores de búsqueda. Para este artículo que estoy tratando de diseñar un sitio web para las personas mantener sus datos de o en línea. Sin embargo, en el futuro, la misma aplicación puede ser utilizada por la gran comunidad en todo el mundo con la funcionalidad y módulos añadido. Así, el diseño debe ser fácilmente adaptable a fin de hacer frente al futuro crecimiento del negocio. En este artículo voy a hablar sobre la creación y el diseño de la interfaz de (UI) de tal manera para que la interfaz de se puede separar de la lógica de negocio, y se pueden crear de forma independiente por cualquier diseñador / desarrollador. Para esta parte vamos a utilizar ASP.Net MVC, Knockout Jquery y Bootstrap. más adelante en este artículo vamos a discutir más sobre el diseño de bases de datos y la aplicación de la lógica de negocio utilizando capas estructuradas utilizando SQL Server 2008, Entity Framework, y el castillo de Windsor para la inyección de dependencias.
L A SEPARACIÓN DE PREOCUPACIÓN : O BJETIVO P RIMARIO El concepto clave es el paso de la mayor parte o toda la lógica. La lógica no debería obligarse a una página. ¿Qué pasa si tenemos que volver a utilizar la lógica de una página en otra? En ese caso vamos a tener la tentación de copiar y pegar. Si hacemos esto, entonces nuestro proyecto se convertirá en mantenible. Otro concepto importante es separar la capa de a datos desde cualquier lógica de negocio, ya que estamos planeando usar Entity Framework esto es un problema menor como EF ya debería tener este final separada. Deberíamos ser capaces de moverse con facilidad a todos nuestros archivos EF a otro proyecto y simplemente añadir una referencia a los proyectos que más lo necesitan. A continuación se muestra el alto nivel de diseño: Y, la solución final se verá como la siguiente imagen en Visual Studio:
S IETE PROYECTOS EN UNA SOLA SOLUCIÓN : ES LO NECESARIO ? Es todo acerca de su decisión ... La propuesta diseñada ofrecerá algunos de los beneficios más relevantes, que incluyen:
La separación de Preocupación: El diseño debe permitir que las capas claras y definidas; significa segregar aplicación en áreas distintas cuya funcionalidad no se superpone. de tal manera que la interfaz de -diseñadores pueden concentrarse en su trabajo sin tener que lidiar con la lógica de negocio (Application.Web), y el desarrollador del núcleo sólo puede trabajar en la lógica de negocio principal (Application.DTO o Application.Manager). Productividad: Es más fácil para agregar nuevas características al software existente, ya que la estructura ya está en marcha, y la ubicación para cada nueva pieza de código se conoce de antemano, por lo que cualquier problema puede ser fácilmente identificados y separados para hacer
frente a la complejidad y al alcanzar los factores de calidad de ingeniería necesarios, como * * robustez, adaptabilidad, capacidad de mantenimiento y reutilización. Capacidad de mantenimiento: Es más fácil mantener la aplicación, debido a despejar y estructura definida del código es visible y conocido, por lo que es más fácil encontrar los errores y anomalías, y modificarlos con un riesgo mínimo. Adaptabilidad: Las nuevas características técnicas, un frente tan diferente termina, o la adición de un motor de reglas de negocio es más fácil de lograr, ya que su arquitectura de software crea una clara separación de las preocupaciones. Reutilización: La reutilización es otro motivo de preocupación en el diseño de cualquier aplicación, ya que es uno de los principales factores para disminuir el costo total de propiedad, y nuestro diseño debe considerar hasta qué punto podemos volver a utilizar la aplicación web creada y diferentes capas. En la última sección de este artículo, vamos a discutir la funcionalidad de cada capa del individuo en detalles.
H ERRAMIENTAS Y T ECNOLOGÍA Para alcanzar la solución final, necesitamos herramientas abajo / dll:
Visual Studio 2012 ASP.NET MVC 4 con Razor View Engine Entity Framework 5.0 Castillo de Windsor por DI SQL Server 2008/2012 Knockout.js y jQuery Castillo de Windsor por DI Bootstrap CSS
L O QUE ESTAMOS TRATANDO DE LOGRAR : R EQUISITO P ANTALLA 1: L ISTA DE OS - V ER TODOS LOS OS 1.1 1.2 1.3 1.4
Esta pantalla debe mostrar todos los os disponibles en la base de datos. El debe ser capaz de eliminar cualquier o. El debe poder editar cualquier información de o. El debe ser capaz de crear un nuevo o. boceto inicial:
P ANTALLA 2: C REAR NUEVO O Esta pantalla debe aparecer una pantalla en blanco para proporcionar funcionalidad que. 2.1 El debe ser capaz de entrar en su / su primer nombre, apellido y dirección de correo electrónico. 2.2 debe poder añadir cualquier cantidad de números de teléfono, haga clic en Agregar números. 2.3 debe poder quitar cualquier número de teléfono. 2.4 debe poder añadir cualquier número de direcciones haciendo clic en Añadir nueva dirección. 2.5 debe poder eliminar cualquier dirección. 2.6 Haga clic en el botón de guardar debe guardar los datos de o en la base de datos y el volverá atrás en la página Lista de os.2.7 Haga clic en el botón Volver al Perfil debían regresar al a la página de o de lista. boceto inicial:
P ANTALLA 3: A CTUALIZACIÓN DE O EXISTENTE Esta pantalla debe mostrar la pantalla con los datos de o de información seleccionados. 3.1 El debe ser capaz de modificar su / su primer nombre, apellido y dirección de correo electrónico. 3.2 El debe poder modificar / borrar / Añadir cualquier cantidad de números de teléfono, haga clic en Agregar números o eliminar enlace. 3.3 El debe poder modificar / borrar / Agregar cualquier número de direcciones haciendo clic en Añadir nueva dirección o eliminar enlace. 3.4 Haga clic en el botón de guardar debe actualizar los datos de o en la base de datos y el volverá de nuevo en la página Lista de os.3.5 Haga clic en el botón Atrás para Perfil debían regresar al a la página de o de lista. Boceto inicial:
P ARTE 1: C REACIÓN DE A PLICACIONES W EB (K NOCKOUT . JS , A SP .N ET MVC Y B OOTSTRAP ): P ARA D ISEÑADORES Antes del saque inicial por parte de IU, vamos a ver qué beneficios nos estamos utilizando Knockoutjs y Bootstrap junto con ASP.NET MVC 4. ¿Por qué Knockoutjs: Knockout es un patrón MVVM que trabaja con un modelo de vista javascript. La razón por la que esto funciona bien con MVC es que la serialización hacia y desde modelos de javascript en JSON es muy simple, y también se incluye con MVC 4. nos permite desarrollar rica interfaz de con mucho menos codificación y cada vez que modificamos nuestros datos, inmediata Refleja en la interfaz de . ¿Por Bootstrap: Twitter Bootstrap es un HTML simple y flexible, CSS y Javascript para los componentes de interfaz de populares e interacciones. Viene con haces de estilos CSS, componentes y plugins Javascript. Proporciona soporte de plataforma cruzada, lo que elimina las principales inconsistencias de diseño. Todo simplemente funciona! Una buena documentación y el sitio web de Twitter Bootstrap en sí es una muy buena referencia para ejemplo de la vida real. Y, por último, me ahorra un montón de veces, ya que redujo el tiempo de desarrollo a la mitad con muy menos casi cero problemas con el navegador de pruebas y. Algunos otros beneficios que podemos obtener mediante el uso de este marco son:
Rejilla 12-Columna, diseño fijo, fluido o diseño sensible. CSS Base para la tipografía, el código (el resaltado de sintaxis con Google prettify), tablas, formularios, botones y utiliza iconos por Glpyhicons.
Componentes Web de interfaz de , como botones, menús de navegación, Etiquetas, Miniaturas, Alertas, barras de progreso y misceláneos. Plugins Javascript para Modal, desplegable, Scrollspy, Tab, Tooltip, Popover, Alerta, Button, Collapse, Carousel y Typehead.
En los pasos siguientes, vamos a trabajar a través de la distribución y el diseño para construir la interfaz de para el requisito anterior utilizando datos ficticios javascript.
P ASO 1: Crear un nuevo proyecto como solución en blanco; el nombre como "Aplicación"
P ASO 2: Haga clic en la carpeta de la solución y Agregar nuevo proyecto de tipo ASP.NET MVC 4 como plantillas de aplicaciones de Internet con vistas al motor como Razor. Después del paso 2 - la estructura del proyecto debe ser similar a la imagen de abajo
P ASO 3: Haga clic derecho sobre referencias y haga clic en istrar paquetes NuGet. Escriba Bootstrap en la barra de búsqueda a continuación, haga clic en el botón Instalar.
P ASO 4:
añadir debajo de la línea de código en el archivo en la carpeta BundleConfig.cs App_Start añadir Knockoutjs y Bootstrap para cada página
bundles.Add (nuevo ScriptBundle ("~ / paquetes / knockout"). Incluir ( "~ / scripts / knockout- {version} .js")); bundles.Add (nuevo StyleBundle ("~ / Content / css") Incluya ("~ / Content / bootstrap.css").); También en _Layout, archivo cshtml en Vistas / carpeta compartida agregar debajo de la línea para registrar archivos knockout como:
@ Scripts.Render ("~ / paquetes / knockout")
P ASO 5: Añadir un nuevo nombre de la carpeta como o dentro Vistas y, a continuación añadir Index.cshtml como nuevo Ver página. A continuación, agregue un nuevo nombre de controlador que Controller.cs dentro de la carpeta del controlador, y añadir un nuevo archivo en la carpeta Scripts .js. Consulte a continuación la imagen.
P ASO 6: Finalmente modificar el mapa de rutas por defecto en Route.config señalar ar controlador como:
routes.MapRoute ( nombre: "Default", url: "{controlador} / {acción} / {id}", predeterminados: nuevo controlador = {"o", action = "Índice", id = UrlParameter.Optional} ); Y también modificar el archivo _Layout.cshtml interior Vista / Shared según la sintaxis BootStrap. A continuación se muestra el código modificado:
<Meta charset = "UTF-8" /> <Title> @ ViewBag.Title - gerente de o
<Meta name = "viewport" content = "width = dispositivo de ancho" /> @ Scripts.Render ("~ / paquetes / jquery") @ Scripts.Render ("~ / paquetes / knockout") @ Styles.Render ("~ / Content / css") @ Scripts.Render ("~ / paquetes / Modernizr") RenderSection ("Scripts", requeridas: false)
Manager
RenderSection ("Presentó", se requiere: false) <Sección> RenderBody ()
& copy; @ DateTime.Now.Year -. Diseño y devloped por Anand Pandey
P ASO 7: Ahora hemos terminado con la configuración inicial para ejecutar la aplicación. La salida es la siguiente: Vamos a utilizar esta página para mostrar el requisito para la pantalla 1, es decir la lista de os - Ver todos los os
P ASO 8: En primer lugar vamos a crear un dato de perfil ficticias como matriz en .js (más tarde vamos a buscarla a la base de datos), y luego vamos a utilizar estos datos para rellenar la cuadrícula.
var DummyProfile = [ { "ProfileID": 1, "Nombre": "Anand", "Apellido": "Pandey", "Correo electrónico": "[email protected]" }, { "ProfileID": 2, "Nombre": "Juan", "Apellido": "Cena", "Correo electrónico": "[email protected]" } ] A continuación, vamos a crear ProfilesViewModel, una clase de modelo de vista que mantienen perfiles, un arreglo que contiene una colección inicial de datos DummyProfile. Tenga en cuenta que se trata de un ko.observableArray, y es el equivalente observable de una serie regular, lo que significa que puede disparar automáticamente las actualizaciones de la interfaz de cada vez que se agregan o eliminan elementos. Y por último tenemos que activar Knockout utilizando ko.applyBindings ().
var ProfilesViewModel = function () { var self = esto; var refresh = function () { self.Profiles (DummyProfile);
}; // propiedades de datos pública self.Profiles ko.observableArray = ([]); refresh (); }; ko.applyBindings (nuevo ProfilesViewModel ());
P ASO 9: A continuación vamos a escribir código en la página Index.cshtml, que se supone que mostrar la Lista de perfiles.Tenemos que utilizar la unión de elemento foreach, por lo que va a hacer una copia de sus elementos secundarios para cada entrada de la matriz de perfiles, y luego poblar que con algunas marcas de decir que quieres una mesa fila () para cada entrada.
Nombre
Apellido
Email
<Script src = "~ / Scripts / .js"> Si ejecuta la aplicación ahora, debería ver una tabla simple de la información del perfil como: Recordar para el estilo de tabla que estamos usando la clase css de Manos a la Obra. En el ejemplo anterior, es;
P ASO 10: Ahora tenemos que añadir Editar y Eliminar la funcionalidad para cada fila, y un botón más en la parte superior para crear un nuevo perfil. Así que vamos a hacer: Añadir uno más
y
en nuestra plantilla de la tabla y se unen es click evento con función removeProfile en js. Modificar fila Nombre añadir enlace para Editar Perfil y luego unirse a su evento click con función EditProfile. Agregar un botón para Crear nuevo perfil y enlazarlo con un clic del evento usando la función createProfile. Así código final hacia fuera para Index.cshtml es:
Nombre
Apellido
Email
quitar <Script src = "~ / Scripts / .js"> Y la salida es: Ninguno del botón agregado y enlace funcionará, porque no hemos escrito ningún código para eso, así que vamos a arreglar eso en el próximo paso.
P ASO 11: Añadir eventos para createProfile, EditProfile y removeProfile en .js
self.createProfile = function () { alert ("Crear un nuevo perfil"); }; self.editProfile = function (perfil) { ("perfil tis Editar con id perfil como:" + profile.ProfileId) alerta; }; self.removeProfile = function (perfil) { if (confirm ("¿Estás seguro que quieres borrar este perfil?")) { self.Profiles.remove (perfil); } }; Ahora cuando ejecutamos nuestra aplicación y haga clic en el botón Eliminar, a continuación, se eliminará ese perfil de la matriz actual. Como definimos esta matriz como observable, la interfaz de se mantendrá en sintonía con los cambios en la matriz. Pruébalo haciendo clic en el botón Quitar. Editar enlace y botón Crear perfil simplemente mostrará la alerta. Así que, vamos a implementamos esta funcionalidad en los siguientes pasos:
P ASO 12: A continuación vamos a añadir:
Un nuevo Razor Vista interior Vistas / o como CreateEdit.cshtml, y registrarlo en la clase Controller.cs.
pública ActionResult CreateEdit () { volver Ver (); } Un nuevo archivo js nombrado como CreateEdit.js dentro de la carpeta Scripts. Modificar createProfile y EditProfile método de .js, por lo que apuntará a la página CreateEdit.
self.createProfile = function () { window.location.href = '/ o / CreateEdit / 0'; }; self.editProfile = function (perfil) { window.location.href = '/ o / CreateEdit /' + profile.ProfileId; }; Ejecución de la aplicación ahora va a trabajar para todos los eventos en la lista de os (-1 pantalla). Y crear y editar debe redirigir a la página CreateEdit con los parámetros requeridos.
P ASO 13: En primer lugar vamos a empezar con la adición de información del perfil a esta página CreateEdit. Por que tenemos que hacer: Tenemos que llegar ProfileID de url es así, añadir por debajo de dos líneas en la parte superior de la página CreateEdit.js
var url = window.location.pathname; var ProfileID = url.substring (url.lastIndexOf ('/') + 1); Definir un maniquí de perfil como matriz en CreateEdit.js Contraer | Copiar código var DummyProfile = [ { "ProfileID": 1, "Nombre": "Anand", "Apellido": "Pandey", "Correo electrónico": "
[email protected]" }, { "ProfileID": 2, "Nombre": "Juan", "Apellido": "Cena", "Correo electrónico": "
[email protected]" } ]
Perfil, un simple constructor de la clase JavaScript que almacena FirstName de un perfil, Apellido y Correo selección.
var Perfil = function (perfil) { var self = esto; self.ProfileId = ko.observable (perfil profile.ProfileId: 0); self.FirstName = ko.observable (perfil profile.FirstName: '?'); self.LastName = ko.observable (perfil profile.LastName: '?'); self.Email = ko.observable (perfil profile.Email: '?'); };
ProfileCollection, una clase de modelo de vista que tiene el perfil (un objeto JavaScript que proporciona datos de perfil), junto con la unión de los eventos saveProfile y backToProfileList.
var ProfileCollection = function () { var self = esto; // Si ProfileID es 0, Significa Crear nuevo perfil if (ProfileID == 0) { self.profile = ko.observable (nuevo perfil ()); } else { var currentprofile = $ .grep (DummyProfile, función (e) {return e.ProfileId == ProfileID;}); self.profile = ko.observable (nuevo perfil (currentprofile [0])); } self.backToProfileList = function () {window.location.href = '/ o'; }; self.saveProfile = function () { alert ("Fecha de ahorrar es:" + JSON.stringify (ko.toJS (self.profile ()))); }; };
Y finalmente, activar Knockout utilizando ko.applyBindings ().
ko.applyBindings (nuevo ProfileCollection ());
P ASO 14: A continuación vamos a escribir código en la página CreateEdit.cshtml, que se supone para mostrar la información del perfil. Tenemos que utilizar el "con" la unión de los datos del perfil, por lo que va a hacer
una copia de sus elementos secundarios para un perfil determinado y, a continuación, asignar los valores apropiados.El código para CreateEdit.cshtml es la siguiente:
Información del perfil
button = "btn btn btn-pequeño éxito" bind-data = 'click: saveProfile'> Guardar class = "btn btn btn-pequeño-primaria" type = "button" value = "Volver al Perfil bind-data = "click: $ root.backToProfileList" />
<Script src = "~ / scripts / CreateEdit.js"> Ejecución de la aplicación mostrará las siguientes pantallas: Para crear Nuevo: Para registro existente con el perfil Id 1: Actualización de cualquier registro existente y haga clic en guardar con dar salida a continuación: Según el requisito de esta pantalla, ya lo hemos hecho: 2.1 El debe ser capaz de entrar en su / su Nombre, Apellido y Dirección de correo electrónico 2.6 Haga clic en el botón de guardar debe guardar los datos de o en la base de datos y el volverá de nuevo en la página Lista de os. 2.7 Haga clic en el botón Atrás para Perfil debían regresar al a la lista de os . página En siguiente paso vamos a tratar de conseguir a continuación requisito: 2.2 El debe poder añadir cualquier cantidad de números de teléfono, haga clic en Agregar números. 2.3 El debe poder quitar cualquier número de teléfono
P ASO 15: Para alcanzar el requisito no. 2.2 y 2.3, tenemos que hacer: Definir un PhoneType maniquí y datos PhoneDTO como una matriz en CreateEdit.js. phoneTypeData se utiliza para enlazar desplegable para definir el tipo de teléfono para un número de teléfono particular.
var phoneTypeData = [ { "PhoneTypeId": 1, "Nombre": "Teléfono del trabajo" }, { "PhoneTypeId": 2, "Nombre": "Tu Nombre" } ]; var PhoneDTO = [ { "PhoneId": 1, "PhoneTypeId": 1, "ProfileID": 1, "Número": "111-222-3333" }, { "PhoneId": 2, "PhoneTypeId": 2, "ProfileID": 1, "Número": "444-555-6666" } ]; Perfil, un simple constructor de la clase de JavaScript que almacena una información de línea telefónica que incluye el tipo de teléfono es decir, si su "teléfono del trabajo" o "Phone Home", etc, junto con el número de teléfono.
Phoneline var = function (teléfono) { var self = esto; self.PhoneId = ko.observable (teléfono phone.PhoneId: 0); self.PhoneTypeId = ko.observable (teléfono phone.PhoneTypeId: 0); self.Number = ko.observable (teléfono phone.Number: ''); }; Modificar la clase viewmodel ProfileCollection también sostiene phoneNumbers junto con la unión de los eventos addPhone y removePhone.
var ProfileCollection = function () { var self = esto; // Si ProfileID es 0, Significa Crear nuevo perfil if (ProfileID == 0) { self.profile = ko.observable (nuevo perfil ()); self.phoneNumbers = ko.observableArray ([nueva línea telefónica ()]); } else { var currentprofile = $ .grep (DummyProfile, función (e) {return e.ProfileId == ProfileID;}); self.profile = ko.observable (nuevo perfil (currentprofile [0])); var currentProfilePhone = $ .grep (PhoneDTO, función (e) {return e.ProfileId == ProfileID;}); self.phoneNumbers = ko.observableArray (ko.utils.arrayMap (currentProfilePhone, función (teléfono) { devolver el teléfono; })); } self.addPhone = function () { self.phoneNumbers.push (nueva línea telefónica ()) }; self.removePhone = function (teléfono) {self.phoneNumbers.remove (teléfono)}; self.backToProfileList = function () {window.location.href = '/ o'; }; self.saveProfile = function () { alert ("Fecha de ahorrar es:" + JSON.stringify (ko.toJS (self.profile ()))); }; };
P ASO 16: A continuación vamos a añadir una sección más que añadir la información del teléfono en la página CreateEdit.cshtml, que se supone para mostrar la información del teléfono. Como un perfil puede tener teléfono múltiple de diferentes tipos, Por lo tanto, vamos a utilizar el "foreach" vinculante para los datos de números de teléfono, por lo que va a hacer una copia de sus elementos secundarios para un perfil determinado, y luego asignar los valores apropiados. Añadir a continuación la sección en CreateEdit.cshtml justo después Información Perfil y antes en el botón Guardar.
Información del teléfono
<Select-bind data = "opciones: phoneTypeData, valor: PhoneTypeId, optionsValue: 'PhoneTypeId', optionsText: 'Nombre', optionsCaption: 'Seleccione Tipo Teléfono ...'">
X
Añadir nuevo teléfono Ahora la salida para agregar nuevo o es: Y para editar o existente es: Así que ahora nos quedamos sólo con el requisito de abajo: . 2.4 debe poder añadir cualquier número de direcciones haciendo clic en Añadir nueva dirección 2.5 El debe poder eliminar cualquier dirección Paso 17: El requisito no. 2.4 y 2.5 son similares a guía telefónica de la Información, a continuación es el código final para CreateEdit.js y archivos CreateEdit.cshtml: Para CreateEdit.js
var url = window.location.pathname; var ProfileID = url.substring (url.lastIndexOf ('/') + 1); var DummyProfile = [ { "ProfileID": 1, "Nombre": "Anand", "Apellido": "Pandey", "Correo electrónico": "
[email protected]" }, { "ProfileID": 2, "Nombre": "Juan", "Apellido": "Cena", "Correo electrónico": "
[email protected]" } ]; var PhoneTypeData = [ { "PhoneTypeId": 1,
"Nombre": "Teléfono del trabajo" }, { "PhoneTypeId": 2, "Nombre": "Tu Nombre" } ]; var PhoneDTO = [ { "PhoneId": 1, "PhoneTypeId": 1, "ProfileID": 1, "Número": "111-222-3333" }, { "PhoneId": 2, "PhoneTypeId": 2, "ProfileID": 1, "Número": "444-555-6666" } ]; var AddressTypeData = [ { "AddressTypeId": 1, "Nombre": "Dirección de envío" }, { "AddressTypeId": 2, "Nombre": "Dirección de facturación" } ]; var AddressDTO = [ { "AddressID": 1, "AddressTypeId": 1, "ProfileID": 1, "AddressLine1": "10000 Richmond Avenue", "AddressLine2": "Apt # 1000", "País": "EE.UU.", "Estado": "Texas", "Ciudad": "Houston", "Código Postal": "70000" }, { "AddressID": 2, "AddressTypeId": 2, "ProfileID": 1,
"AddressLine1": "20000 Highway 6", "AddressLine2": "Suite # 2000", "País": "EE.UU.", "Estado": "Texas", "Ciudad": "Houston", "Código Postal": "80000" } ];
var Perfil = function (perfil) { var self = esto; self.ProfileId = ko.observable (perfil profile.ProfileId: 0); self.FirstName = ko.observable (perfil profile.FirstName: '?'); self.LastName = ko.observable (perfil profile.LastName: '?'); self.Email = ko.observable (perfil profile.Email: '?'); self.PhoneDTO = ko.observableArray (perfil profile.PhoneDTO: []?); self.AddressDTO = ko.observableArray (perfil profile.AddressDTO: []?); }; Phoneline var = function (teléfono) { var self = esto; self.PhoneId = ko.observable (teléfono phone.PhoneId: 0); self.PhoneTypeId = ko.observable (teléfono phone.PhoneTypeId: 0); self.Number = ko.observable (teléfono phone.Number: ''); }; AddressLine var = function (dirección) { var self = esto; self.AddressId = ko.observable (dirección address.AddressId: 0); (? dirección address.AddressTypeId: 0) self.AddressTypeId = ko.observable; self.AddressLine1 = ko.observable (dirección address.AddressLine1: ''); self.AddressLine2 = ko.observable (dirección address.AddressLine2: ''); self.Country = ko.observable (dirección address.Country: ''); self.State = ko.observable (dirección address.State: ''); self.City = ko.observable (? dirección address.City: ''); self.ZipCode = ko.observable (? dirección address.ZipCode: ''); };
var ProfileCollection = function () { var self = esto; // Si ProfileID es 0, Significa Crear nuevo perfil if (ProfileID == 0) { self.profile = ko.observable (nuevo perfil ()); self.phoneNumbers = ko.observableArray ([nueva línea telefónica ()]); self.addresses = ko.observableArray ([nuevo AddressLine ()]); }
else { // Para obtener información del perfil var currentprofile = $ .grep (DummyProfile, función (e) {return e.ProfileId == ProfileID;}); self.profile = ko.observable (nuevo perfil (currentprofile [0])); // Números de teléfonos var currentProfilePhone = $ .grep (PhoneDTO, función (e) {return e.ProfileId == ProfileID;}); self.phoneNumbers = ko.observableArray (ko.utils.arrayMap (currentProfilePhone, función (teléfono) { devolver el teléfono; })); Para // Dirección var currentProfileAddress = $ .grep (AddressDTO, función (e) {return e.ProfileId == ProfileID;}); self.addresses = ko.observableArray (ko.utils.arrayMap (currentProfileAddress, función (dirección) { la dirección del remitente; })); } self.addPhone = function () {self.phoneNumbers.push (nueva línea telefónica ())}; self.removePhone = function (teléfono) {self.phoneNumbers.remove (teléfono)}; self.addAddress = function () {self.addresses.push (nuevo AddressLine ())}; self.removeAddress = function (dirección) {self.addresses.remove (dirección)}; self.backToProfileList = function () {window.location.href = '/ o'; }; self.saveProfile = function () { self.profile () AddressDTO = self.addresses.; self.profile () PhoneDTO = self.phoneNumbers.; alert ("Fecha de ahorrar es:" + JSON.stringify (ko.toJS (self.profile ()))); }; }; ko.applyBindings (nuevo ProfileCollection ()); y, por CreateEdit.cshtml
Información del perfil
Información del teléfono
<Select-bind data = "opciones: PhoneTypeData, valor: PhoneTypeId, optionsValue: 'PhoneTypeId', optionsText: 'Nombre', optionsCaption: 'Seleccione Tipo Teléfono ...'">
X
Añadir nuevo teléfono
Dirección de Información
<Select-bind data = "opciones: AddressTypeData, valor: AddressTypeId, optionsValue: 'AddressTypeId', optionsText: 'Nombre', optionsCaption: 'Seleccione Tipo de dirección ...'">
X
Añadir nueva dirección
Guardar perfil
<Script src = "~ / scripts / CreateEdit.js"> Así que finalmente, aplicación mostrará las pantallas como por la exigencia: Pantalla 1: Lista de os Ver todos los os de la pantalla 2: Crear nuevo o - Esta pantalla debe aparecer una pantalla en blanco para proporcionar funcionalidad que. Pantalla 3: Actualización de o existente - Esta pantalla debe pantalla con los datos de o de información seleccionados.
V ALIDACIÓN : Casi hemos terminado con el diseño parte de nuestra aplicación .El único que queda ahora, es la gestión de la validación cuando el botón el hace clic en "Guardar". La validación es el principal requisito y ahora parte más ignorante de un día para cualquier aplicación web. Por una correcta validación, el puede saber lo que hay datos que deben registrarse. A continuación en este artículo, voy a discutir biblioteca KnockoutJS validación que se puede descargar usando NuGet. Vamos a ver algunos de los escenarios de validación más comunes y la forma de lograrlo mediante la validación por nocaut. Escenario 1: Nombre es un campo obligatorio en forma this.FirstName = ko.observable () extendemos ({requerido: true}).;Escenario 2: El número máximo de caracteres para el nombre no debe exceder de 50 y no debe ser menos de 3 caracteres this.FirstName = ko.observable () extender ({maxLength: 50, minLength: 3});.Escenario 4: La edad es un campo obligatorio en la forma, y debe ser siempre mayor que 18 y menor que 100 . this.Age = ko.observable () se extienden ({required: true, máx: 100, min: 18});Escenario 5: El correo electrónico es una campo obligatorio y debe estar en formato de correo electrónico correcta this.Email = ko.observable () se extienden ({required: true, email: true});.Escenario 6: Fecha de Nacimiento es un campo
obligatorio y debe estar en formato adecuado fecha deesta . .DateOfBirth = ko.observable () extender ({required: true, fecha: true}); Escenario 7: El precio es un campo obligatorio y debe ser en número adecuado o formato decimal this.Price = ko.observable () se extienden. ({required: true, cantidad: true}); Escenario 8: Número de Teléfono es un campo obligatorio y debe estar en buen formato US Nota: Un número de teléfono válido de EE.UU. tiene el siguiente formato: 1-XDD-XDD-dddd El "1 - "al principio de la cadena es opcional y también lo son los guiones. x es cualquier dígito entre 2 y 9, mientras que d puede ser cualquier dígito. this.Phone = ko.observable () se extienden ({required: true, n∫mero de: true});. Escenario 9: campo ToDate debe ser mayor que el campo FromDate
this.ToDate = ko.observable (). extend ({ igual: function () {return (valor> $ ('# FromDate') val ().)? val: val + "|"} }); Escenario 10: Número de teléfono debe aceptar solamente - + () 0-9 de s regex var = / \ (? ([0-9] {3}) \)? ([.-]?) ([0-9] {3}) \ 2 ([0-9] {4}) / . this.PhoneNumber = ko.observable () extender ({patrón: regex});
Así que, ahora hemos visto diferentes tipos de escenarios de validación y su sintaxis; ahora vamos a ponerlo en práctica en nuestra aplicación. Por esa primera descarga los knockout.validation.js biblioteca utilizando NuGet. En este momento nuestro script de validación está totalmente terminada y debería tener este aspecto:
var Perfil = function (perfil) { var self = esto; self.ProfileId = ko.observable (perfil profile.ProfileId: 0?) .extend ({required: true}); self.FirstName = ko.observable (? perfil profile.FirstName: '') .extend ({required: true, maxLength: 50}); self.LastName = ko.observable (? perfil profile.LastName: '') .extend ({required: true, maxLength: 50}); self.Email = ko.observable (? perfil profile.Email: '') .extend ({required: true, maxLength: 50, correo electrónico: true}); self.PhoneDTO = ko.observableArray (perfil profile.PhoneDTO: []?); self.AddressDTO = ko.observableArray (perfil profile.AddressDTO: []?); }; Phoneline var = function (teléfono) { var self = esto; self.PhoneId = ko.observable (teléfono phone.PhoneId: 0); self.PhoneTypeId = ko.observable (? teléfono phone.PhoneTypeId: no definido) .extend ({required: true}); self.Number = ko.observable (phone.Number teléfono: ''?) .extend ({required: true, maxLength: 25, n∫mero de: true}); }; AddressLine var = function (dirección) { var self = esto; self.AddressId = ko.observable (dirección address.AddressId: 0); self.AddressTypeId = ko.observable (? dirección address.AddressTypeId: no definido) .extend ({required: true}); self.AddressLine1 = ko.observable (address.AddressLine1 dirección: ''?) .extend ({required: true, maxLength: 100}); self.AddressLine2 = ko.observable (address.AddressLine2 dirección: ''?) .extend ({required: true, maxLength: 100}); self.Country = ko.observable (address.Country dirección: ''?) .extend ({required: true, maxLength: 50}); self.State = ko.observable (address.State dirección: ''?) .extend ({required: true, maxLength: 50}); self.City = ko.observable (? dirección address.City: '') .extend ({required: true, maxLength: 50}); self.ZipCode = ko.observable (? dirección address.ZipCode: '') .extend ({required: true, maxLength: 15}); };
Después de la validación de nuestra solución final se parece a la pantalla siguiente después de hacer clic en el botón "Guardar": Hasta ahora, hemos hablado acerca de la consecución de nuestro interfaz de sin conocer cualquier aplicación efectiva (bases de datos de interacción) es decir, la interfaz de se crea de forma independiente por cualquier diseñador / desarrollador sin conocer el negocio actual la lógica. !!! Eso es genial !!! A continuación, voy a hablar sobre cómo diseñar la base de datos y la forma de aplicar la lógica de negocio utilizando capas estructuradas.
P ARTE 2: C REAR D ISEÑO DE BASE DE DATOS (SQL S ERVER 2008 R 2): P ARA DBA Desde el diseño de base de datos prospectiva a continuación son las principales funcionalidades que deben ser cumplidas:
Un o puede tener Primer nombre, Apellido y Correo electrónico. Un o puede tener varias direcciones. Un o puede tener varios números de teléfono.
. Para lograr la funcionalidad de gestión de os, por debajo de diseño de base de datos se ha utilizado la relación entre las tablas son según abajo diagrama de base de datos:
P ARTE 3: D ISEÑO DE CAPAS LÓGICAS : P ARA C ORE D ESARROLLADORES Como se señaló anteriormente, nuestra estructura final es: A continuación vamos a discutir la estructura general para nuestra aplicación, en términos del grupo lógico de los componentes en capas separadas, que se comunica con los demás con / sin restricciones y cada lógica tiene sus propias metas. Las capas son un estilo arquitectónico, y que resuelve los problemas de mantenimiento y de mejora en el largo plazo. Así que vamos a proceder con la adición de una biblioteca de clases en nuestra solución y la nombramos como Application.Common.
A PPLICATION .C OMMON : Esta es una aplicación de biblioteca de clases, con alguna funcionalidad común y puede ser utilizado por diferentes capas lógicas. Por ejemplo, de seguridad, de registro, seguimiento, validación, etc Los componentes definidos en esta capa no sólo pueden reutilizar por otras capas en esta solución, pero también puede ser utilizar por otras aplicaciones. Para que sea más fácil cambiar en el futuro, podemos utilizar la inyección de dependencias y la abstracción, con un cambio mínimo en nuestra aplicación. Por ejemplo, en esta capa que vamos a utilizar, un componente validador para validar la entrada de datos, y Logger personalizado para registro de errores . o advertencia continuación se muestra la captura de pantalla de la carpeta después de añadir la solución de biblioteca de clases común: A continuación, vamos a añadir una biblioteca de clases en nuestra solución y el nombre como Application.Core.
A PPLICATION .C ORE : Los componentes de esta capa implementan la funcionalidad básica del sistema y encapsulan toda la lógica de negocio relevantes. Básicamente, esta capa normalmente contiene clases que implementan la lógica de dominio dentro de sus métodos. Esta capa también define una Unidad de Contrato de trabajo dentro de la capa de núcleo por lo que será capaz de cumplir con el principio de PI. El objetivo principal es diferenciar y separar claramente el comportamiento del dominio / negocio principal y los detalles de implementación de infraestructura, tales como el a datos y repositorios específicos ligados a una tecnología particular como ORM, o simplemente las bibliotecas de a datos o incluso aspectos transversales de la arquitectura. De este modo, mediante el aislamiento de la funcionalidad de la aplicación Core, vamos a aumentar drásticamente la capacidad de mantenimiento de nuestro sistema y se podría incluso reemplazar las capas inferiores ( a datos, ORM, y bases de datos) con bajo impacto para el resto de la aplicación. A continuación, vamos a añadir una biblioteca de clases en nuestra solución y el nombre como Application.DAL.
A PPLICATION .DAL: La responsabilidad de CHA es y proporciona a los datos y operaciones de persistencia contra la base de datos de almacenamiento; mantener varias sesiones y la conexión con la base de datos múltiple, etc El objetivo principal aquí es envolver la EF Contexto con una interfaz / contrato por lo que podemos usarlo desde el Pesebre y capas de núcleo sin dependencias directos a EF. Los componentes de persistencia de datos proporcionan a los datos alojados dentro de los límites de nuestro sistema (por ejemplo, nuestra principal base de datos que está dentro de un contexto específico LIMITADO), y también a los datos expuestos fuera de los límites de nuestro sistema, como los servicios Web de exterior sistemas. Por lo tanto, tiene componentes como "Repositorios" que proporcionan dicha funcionalidad para acceder a los datos alojados dentro de los límites de nuestro sistema, o "agentes de servicio" que consumen servicios Web expuestos por otros sistemas de back-end externos. Además, esta capa por lo general tienen clases base / componentes con código reutilizable para todas las clases de repositorios. Siguiente, vamos a agregar una biblioteca de clases en nuestra solución y el nombre como aplicación. Repositorio.
A PPLICATION .R EPOSITORY : Esta es una biblioteca de clases y puede ser accesible sólo por Application.Manager. Para cada principal entidad raíz en nuestro dominio, tenemos que crear un repositorio. Básicamente, repositorios son clases / componentes que encapsulan la lógica requerida para acceder a las fuentes de datos de la aplicación. Por lo tanto, centralizar la funcionalidad común de a datos por lo que la aplicación puede tener una mejor capacidad de mantenimiento y la disociación entre la tecnología y la lógica de propiedad de la capas "Core". "Manager" ySiguiente, vamos a agregar una biblioteca de clases en nuestra solución y el nombre de como aplicación. DTO.
A PPLICATION .DTO: De nuevo, esto es una biblioteca de clases, que contiene diferentes clases de contenedor que expone propiedades y métodos, pero no se comunican entre la capa de presentación (Application.Web) y Service Layer (Application.Manager). Un objeto de transferencia de datos es un objeto que se utiliza para encapsular los datos, y enviarlo de un subsistema de una aplicación a otra. Aquí vamos a utilizar dtos por la capa de Manager para transferir datos entre él mismo y la capa de interfaz de . El beneficio principal aquí es que reduce la cantidad de datos que necesita ser enviado a través del cable en
aplicaciones distribuidas. ¡Son también grandes modelos en el patrón MVC. También podemos utilizar DTO para encapsular parámetros para llamadas a métodos. Esto puede ser útil si un método toma más de 4 o 5 parámetros. A continuación, vamos a agregar una biblioteca de clases en nuestra solución y el nombre como aplicación. Manager.
A PPLICATION .M ANAGER : Esta es una biblioteca de clases y puede ser accesible sólo por Application.Web. Para cada módulo hay que declarar uno Manager. Las principales responsabilidades de Manager son aceptar la solicitud de capa / interfaz de Web, entonces comunicarse con los repositorios necesarios y manipular datos en función de la condición después vuelva de nuevo la respuesta. Esta capa intermedia entre la interfaz de y Repositorios.
A PPLICATION .W EB :
En el artículo anterior, ya hemos implementado esta capa usando Javascript datos ficticios. Esta es la aplicación web ASP.NET MVC independiente, y sólo contiene componentes de interfaz de , como html, .aspx, cshtml, MVC, etc Puede también ser cualquier aplicación de Windows. Se comunica con algunos métodos de capa gerente, luego de evaluar los resultados y elegir si desea mostrar un error o page1 o page2 etc etc Esta utilización capa javascript para cargar un modelo para la presentación, pero los datos se procesan en el servidor a través de un ajax . solicitud, por lo que el servidor sólo manejar la lógica de negocio y el javascript gestiona la lógica de presentación Para entender mejor cómo las capas se comunican entre sí, recordemos el requisito inicial:
P ANTALLA 1: L ISTA DE OS - V ER TODOS LOS OS 1.1 Esta pantalla debe mostrar todos los os disponibles en la base de datos. 1.2 El debe ser capaz de eliminar cualquier o. 1.3 El debe poder editar cualquier información de o. 1.4 El debe ser capaz de crear un nuevo o. Para rellenar los datos de la cuadrícula, en carga de la página, lo llamamos GetAllProfiles () método de Controller. Este método devuelve existen todos los perfiles en la base de datos como un objeto JSON, a continuación enlazamos con self.Profiles objeto JavaScript. A continuación se muestra el código para llamar GetAllProfiles () de .js:
var ProfilesViewModel = function () { var self = esto; var url = "/ o / GetAllProfiles"; var refresh = function () { $ .getJSON (Url, {}, función (datos) { self.Profiles (datos); }); }; El botón Quitar clic llamamos DeleteProfile () método de Controller. Este método devuelve elimina ese perfil de base de datos. A continuación se muestra el código para llamar DeleteProfile () desde .js:
self.removeProfile = function (perfil) { if (confirm ("¿Estás seguro que quieres borrar este perfil?")) { Identificación del var = profile.ProfileId; waitingDialog ({}); $ .ajax ({ Tipo: 'Eliminar', url: 'o / DeleteProfile /' + id, éxito: function () {self.Profiles.remove (perfil); }, error: function (err) { error var = JSON.parse (err.responseText); . $ ("
") html (Error.message) .dialog ({modal: true, título: "Error", botones: {"Ok": function () {$ (this) .dialog ("close"); }}}) Show ().; }, completa: function () {closeWaitingDialog (); } }); } }; Por tanto Crear nuevo botón y Editar enlace, sólo redirigir a la página CreateEdit con id como 0 para Crear nuevo y para editar el perfil id de la fila seleccionada. A continuación se muestra el código para createProfile y EditProfile de .js:
self.createProfile = function () { window.location.href = '/ o / CreateEdit / 0'; }; self.editProfile = function (perfil) { window.location.href = '/ o / CreateEdit /' + profile.ProfileId; }; A continuación se muestra la representación de un diagrama de comunicación entre tres capas principales:
P ANTALLA 2: C REAR NUEVO O Esta pantalla debe aparecer una pantalla en blanco para proporcionar funcionalidades como. 2.1 El debe ser capaz de entrar en su / su primer nombre, apellido y dirección de correo electrónico. 2.2 debe poder añadir cualquier cantidad de números de teléfono, haga clic en Agregar números. 2.3 debe poder quitar cualquier número de teléfono. 2.4 debe poder añadir cualquier número de direcciones haciendo clic en Añadir nueva dirección. 2.5 debe poder eliminar cualquier dirección. 2.6 Haga clic en el botón de guardar debe guardar los datos de o en la base de datos y el volverá atrás en la lista de os página.2.7 Haga clic en el botón Volver al Perfil debían regresar al a la página de o de lista.
P ANTALLA 3: A CTUALIZACIÓN DE O EXISTENTE Esta pantalla debe mostrar la pantalla con los datos de o de información seleccionados. 3.1 El debe ser capaz de modificar su / su primer nombre, apellido y dirección de correo electrónico. 3.2 El debe poder modificar / borrar / Añadir cualquier cantidad de números de teléfono, haga clic en Agregar números o eliminar enlace. 3.3 El debe poder modificar / borrar / Agregar cualquier número de direcciones haciendo clic en Añadir nueva dirección o eliminar enlace. 3.4 Haga clic en el botón de guardar debe actualizar los datos de o en la base de datos y el volverá de nuevo en la página Lista de os.3.5 Haga clic en el botón Atrás para Perfil debían regresar al a la página de o de lista. Como se discutió en la aplicación anterior, tanto para la "Nueva creación" y "Editar existente" requisito de que estamos utilizando una sola página como CreateEdit.cshtml, identificando el valor URL para ProfileID es decir, si ProfileID en URL es 0, entonces es la solicitud para la creación de un nuevo perfil, y si se trata de algún valor, la petición es para editar el perfil existente. Debajo Identificación los detalles de implementación: En cualquier caso (Crear o Editar), en la página de carga que necesitan para inicializar los datos para PhoneType y AddressType. Para ello contamos con un método en Controller como InitializePageData (). A continuación se muestra el código en CreateEdit.js inicializar ambas matrices:
AddressTypeData var; var PhoneTypeData; $ .ajax ({ url: url + '/ InitializePageData', asíncrono: false, Tipo datos: 'json', éxito: function (json) { AddressTypeData = json.lstAddressTypeDTO; PhoneTypeData = json.lstPhoneTypeDTO; } });
A continuación, Para Editar perfil que necesita para obtener los datos del perfil, para que tengamos método GetProfileById () en nuestro Controller. Modificamos nuestro código CreateEdit.js existente como:
$ .ajax ({ url: url + '/ GetProfileById /' + ProfileID, asíncrono: false, Tipo datos: 'json', éxito: function (json) { self.profile = ko.observable (nuevo perfil (JSON)); self.phoneNumbers = ko.observableArray (ko.utils.arrayMap (json.PhoneDTO, función (teléfono) { devolver el teléfono; })); self.addresses = ko.observableArray (ko.utils.arrayMap (json.AddressDTO, función (dirección) { la dirección del remitente; })); } }); Por último, Para Guardar datos que tenemos dos métodos en la base de datos. Método Si es Crear nuevo la que llamaremos SaveProfileInformtion () de Controller demás nosotros te llamamos método UpdateProfileInformation (). Modificamos nuestro código CreateEdit.js existente como:
$ .ajax ({ Tipo: (self.profile () ProfileID> 0 'PUT':.? "post"), cache: true, Tipo datos: 'json', url: url + (self.profile () ProfileID> 0 '/ UpdateProfileInformation id =?' +.? . self.profile () ProfileID: '/ SaveProfileInformation'), datos: JSON.stringify (ko.toJS (self.profile ())), contentType: 'application / json; charset = UTF-8 ', asíncrono: false, éxito: function (data) { window.location.href = '/ o'; }, error: function (err) { var err = JSON.parse (err.responseText); errores var = ""; for (var clave en err) { if (err.hasOwnProperty (clave)) { errores + = key.replace (". perfil", "") + ":" + err [clave]; } } $ ("
") html (errores) .dialog ({modal:. Cierto, Título: JSON.parse (err.responseText) .message, botones: {"Ok":
function () {$ (this) .dialog ("close"); }}}) Show ().; }, completar: function () { } });
C ONCLUSIÓN Eso es todo !!! Espero que disfrutes de este artículo. Yo no soy un experto, y también que no he seguido la norma de toda la industria en el momento de escribir este artículo. Y eso, en pocas palabras, es todo lo que sé para empezar el diseño de ASP.NET MVC 4 aplicación. Espero que hayan disfrutado este tutorial y aprendido algo.Todo comentario / Voto son más que bienvenidos .... , Si usted tiene alguna pregunta no dude en preguntar;Estaré encantado de hablar más en los comentarios. Gracias por su tiempo!
C ÓMO UTILIZAR EL CÓDIGO Descargar archivo de comandos de base de datos aquí: Application_DB.sql Contiene SQL Script para crear la entrada de base de datos y tabla principal para la tabla PhoneType y AddressType. Para ejecutar esta aplicación a su entorno de Visual Studio se debe habilitar "Permitir NuGet para descargar los paquetes perdidos durante la construcción". O bien, consulte las siguientes link: http://docs.nuget.org/docs/workflows/using-Nuget-sin-cometen-packages Y, por último, modificar la
cadena de conexión en proyecto Application.Web.
R EFERENCIAS
http://knockoutjs.com/ https://github.com/ericmbarnard/Knockout-Validation/wiki/Configuration http://twitter.github.com/bootstrap/ http://docs.castleproject.org/Windsor.MainPage.ashx http://microsoftnlayerapp.codeplex.com/ http://msdn.microsoft.com/en-us/library/ff921348.aspx
Última edición 17 de enero 2013 a las 22:41 por anandranjanpandey , la versión 5
Descargas ACTUAL
o App Manager utilizando ASP.NET MVC 4
FECHA
Jue 17 de enero 2013 a las 7:00 am
ESTADO
Estable
D ESCARGAS P UNTUACIÓ
12.813
N
19 puntuaciones Opina sobre este comunicado de
EL DE MÁS AYUDA Gracias señor por un artículo tan agradable y completa. muy buena! Ver todas las críticas Los anuncios por desarrollador Medios
ACTIVIDAD
PÁGINAS VISTAS
VISITAS
D ESCARGAS
1491
972
158
Días: 7 30 Todos Detalles
Related Documents
Apuntes Asp En Sharp Develop June 2022 0
Sharp Develop June 2021 0
Sharp Develop April 2020 25
Asp July 2020 6
Ejemplos En Asp December 2022 0
Introduccion Asp April 2021 0
Our Company
2008 Columbia Road Wrangle Hill, DE 19720
+302-836-3880
[email protected]
Quick Links
About
Help / FAQ
Legal
of Service
Cookie Policy
Disclaimer
Follow Us
Mobile Apps
Copyright © 2025 IDOUB.
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-144860406-1');
1n5d1o