Prueba práctica de la entrevista de la API web -- # campo con asp.net campo con mvc campo con api camp codereview Relacionados El problema

Web API Interview Practical Test


4
vote

problema

Español

Hace una semana, solicité una "pasantía de ingeniería de software" en una de las compañías. Como conozco C ++, C #, Java, bien y ha trabajado en un par de proyectos de MVC ASP.NET con MS SQL Server antes, sabía que estaba bien calificado para el trabajo. Además, recientemente me gradué de mi Licenciatura en Ciencias de la Computación con un promedio de alta distinción, así que esta oportunidad era exactamente lo que estaba buscando.

He enviado mi solicitud y fue preseleccionado para una entrevista telefónica. Estaba muy entusiasmado y un par de días después de que recibí una llamada telefónica de HR y me dijeron que mis conjuntos de habilidades eran perfectos y quieren que haga una prueba práctica antes de pasar a cara a cara. La señora me dijo que estaba muy segura de que podría romper la prueba práctica y pedirían algunas preguntas relacionadas con la base de datos en la prueba.

Antes de la prueba práctica, comencé a estudiar mucho SQL, hice todas las preguntas que pude encontrar en Internet y fue bastante seguro. En el día de la prueba práctica, ella me envió un correo electrónico con PDF con las preguntas.

Me dijeron que tenía 4 horas para completar esas tareas. Cuando miré por primera vez las preguntas, me sorprendió bastante ya que no esperaba que las preguntas estuvieran sobre este tema. Me preparé para SQL. Jaja, nunca había programado la API web antes, pero había hecho aplicaciones web de ASP.NET MVC y sabía que podemos crear API en el controlador que pueden devolver los datos de JSON que pueden consumirlos por el cliente utilizando las llamadas AJAX.

Por lo tanto, para la primera tarea, estaba pensando en usar el marco de entidades que se conectan con el archivo de la base de datos y la asignación de objetos, pero en la segunda tarea mencionó que no usaría el marco de la entidad, así que tuve que usar algo más. Al final, utilicé formato XML para almacenamiento de datos porque era fácil manualizar un archivo XML para fines de depuración.

MI Category clase se ve así:

  [Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)     {         Name = name;         Childs = new List<Category>();     } }   

Toda la idea fue que crearía una estructura de datos de categoría usando esa clase y usaría XmlSerializer para serializarlo y deserializarlo desde y desde un archivo.

Después de eso, me dirigí a la tarea 2, que era crear una API web. Tuve 2 opciones aquí, use el proyecto API web en Visual Studios para crear esas API o usar la clase del controlador MVC para crearlas. Nunca he usado API web antes y como solo tuve tiempo limitado para completar la tarea, decidí ir con la segunda opción. Aprender a usar WebAPI podría haber tomado otra hora y no tuve mucho tiempo, pero si estuviera trabajando sin el límite de tiempo, definitivamente habría ido a la ruta de WebAPi.

Aquí están mis funciones de API que el cliente puede consumir. Lo mantuve todo en el archivo homecontoller.cs:

  public class HomeController : Controller {     //Index view, pretty simple one     public ActionResult Index()     {         return View();     }      //API that refreshes the category structure, created this just for debugging     public void RefreshStructure()     {         Category category = new Category("root");         category.Childs.Add(new Category("English"));         category.Childs.Add(new Category("History"));         category.Childs.Add(new Category("Science"));         category.Childs.ElementAt(0).Childs.Add(new Category("Literature"));         category.Childs.ElementAt(0).Childs.Add(new Category("Language"));         category.Childs.ElementAt(2).Childs.Add(new Category("Biology"));         category.Childs.ElementAt(2).Childs.Add(new Category("Chemistry"));         category.Childs.ElementAt(2).Childs.Add(new Category("Physics"));         saveAllCategories(category);     }      //Creates root category from XML file     private Category getAllCategories()     {         XmlSerializer xmlS = new XmlSerializer(typeof(Category));         FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open, FileAccess.Read, FileShare.Read);         Category category = (Category)xmlS.Deserialize(readFileStream);         readFileStream.Close();         return category;     }      //Save Categories to XML file     private void saveAllCategories(Category categories)     {         XmlSerializer xmlS = new XmlSerializer(typeof(Category));         TextWriter textWriter = new StreamWriter(Server.MapPath("~/datamodel/model.xml"));         xmlS.Serialize(textWriter, categories);         textWriter.Close();     }      //Navigates to particulate category     private Category navigateToCategory(IEnumerable<string> path, Category root)     {         Category destination = root;          if (path.Count() == 1)  //It has got to be the root         {             return root;         }         else         {             for (int i = 1; i < path.Count(); ++i)             {                 destination = destination.Childs.FirstOrDefault(c => c.Name == path.ElementAt(i));                 if (destination == null)    //Opps that is a problem, path doesn't exist                 {                     return null;                 }             }         }         return destination;     }      //Creates ouput that can be sent as Json. Categories name separated by ~     private string getDelimiterSeparatedCategories(Category category)     {         string retVal = category.Name;         foreach (var c in category.Childs)         {             retVal += "~" + c.Name;         }         return retVal;     }      //API to create Category     [HttpPost]     public JsonResult CreateCategory(IEnumerable<string> path, string name)     {         Category root = getAllCategories();         Category destination = navigateToCategory(path, root);         if (destination == null)         {             return Json(new { Result = "ERROR" });         }          destination.Childs.Add(new Category(name));         string retVal = getDelimiterSeparatedCategories(destination);         saveAllCategories(root);         return Json(new { Result = "OK", Data =  retVal});     }      //API to retrieve category     [HttpPost]     public JsonResult RetrieveCategories(IEnumerable<string> path)     {         Category root = getAllCategories();         Category destination = navigateToCategory(path, root);         if (destination == null)         {             return Json(new { Result = "ERROR" });         }          string retVal = getDelimiterSeparatedCategories(destination);         return Json(new { Result = "OK", Data = retVal });     }      //API to update category     [HttpPost]     public JsonResult UpdateCategory(IEnumerable<string> path, string name)     {         if (path.Count() == 1)         {             return Json(new { Result = "ERROR" });         }          Category root = getAllCategories();         Category destination = navigateToCategory(path, root);         if (destination == null)         {             return Json(new { Result = "ERROR" });         }          destination.Name = name;         string retVal = getDelimiterSeparatedCategories(destination);         saveAllCategories(root);         return Json(new { Result = "OK", Data = retVal });     }      //API to delete category     [HttpPost]     public JsonResult DeleteCategory(IEnumerable<string> path)     {         if (path.Count() == 1)         {             return Json(new { Result = "ERROR" });         }          List<string> pathParent = new List<string>();          for (int i = 0; i < path.Count() - 1; ++i)         {             pathParent.Add(path.ElementAt(i));         }          Category root = getAllCategories();         Category parent = navigateToCategory(pathParent.AsEnumerable(), root);         Category destination = navigateToCategory(path, root);          if (destination == null)         {             return Json(new { Result = "ERROR" });         }          parent.Childs.Remove(destination);         saveAllCategories(root);         string retVal = getDelimiterSeparatedCategories(parent);         return Json(new { Result = "OK", Data = retVal });     } }   

Como puede ver, tengo 4 API expuestos para que el cliente consuma:

  • CreateCategory
  • RetrieveCategories
  • UpdateCategory
  • DeleteCategory

Después de terminar de aquellos, continué creando el cliente que podría consumir esas APIs:

  @{     ViewBag.Title = "Home Page"; }  <h1 id="CurrentCategory"></h1>  <div id="CategoriesList"></div>  <input type="text" placeholder="Add Category" id="CategoryName" /><button onclick="addCategory()">Add Category</button><br /> <input type="text" placeholder="Update Category" id="NewName" /><button onclick="updateCategory()">Update Category</button><br /> <button onclick="deleteCategory()">Delete Category</button>  @section scripts { <script type="text/javascript">     var cList = document.getElementById("CategoriesList");     var cCategory = document.getElementById("CurrentCategory")     var pArray = new Array();     pArray[0] = "root";     retrieveCategories();      function retrieveCategories() {         $.ajax({             url: '@Url.Action("RetrieveCategories", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray },             success: function (data) {                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href="javascript:gotoParticularCategories('" + categories[i] + "')">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     }      function getCategoriesList(input) {         var retVal = input.split("~");         return retVal;     }      function gotoParticularCategories(category) {         pArray[pArray.length] = category;         retrieveCategories();     }      function deleteCategory() {         $.ajax({             url: '@Url.Action("DeleteCategory", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray },             success: function (data) {                 if (data.Result != "ERROR") {                     pArray.splice(pArray.length - 1, 1);                 }                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href="javascript:gotoParticularCategories('" + categories[i] + "')">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     }      function addCategory() {         var categoryName = document.getElementById("CategoryName").value;         $.ajax({             url: '@Url.Action("CreateCategory", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray, name: categoryName },             success: function (data) {                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href="javascript:gotoParticularCategories('" + categories[i] + "')">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     }      function updateCategory() {         var categoryName = document.getElementById("NewName").value;         $.ajax({             url: '@Url.Action("UpdateCategory", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray, name: categoryName },             success: function (data) {                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href="javascript:gotoParticularCategories('" + categories[i] + "')">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     } </script>     }   

Sé que mi código podría haber sido estructurado mucho mejor, pero realmente estaba tratando de terminar esto en el tiempo y si tuviera tiempo, lo habría refactorado, así que parecía mucho mejor. Para el cliente, estoy usando las llamadas AJAX para llamar a las API que había creado antes.

Al final, tuve una aplicación web funcional que hizo todo lo que pidieron y la envié a ellos a tiempo, pero me preocupa que podría no haber sido suficiente. Siento que podría haberlo hecho mucho mejor y realmente me apasiona la programación y realmente quiero esta pasantía. Ya han pasado 2 días y no se han contactado y realmente me estresamos.

Solo quería preguntar si crees que hice lo suficiente para pasarlo o no.

Si desea descargar el proyecto y jugar con él, es >> aquí .

Original en ingles

A week ago, I applied for a 'Software Engineering Internship' at one of the company. Since I know C++, C#, Java well and have worked on couple of ASP.NET MVC projects with MS SQL server before, I knew I was well qualified for the job. Plus, I recently graduated from my Bachelor of Computer Science with High Distinction average so this opportunity was exactly what I was looking for.

I sent out my application and was shortlisted for a phone interview. I was really excited and couple of days after I got a phone call from HR and they told me that my skill sets were perfect and they want me to do a practical test before moving on to face to face interview. The lady told me that she was very confident that I would be able to smash the practical test and they would ask some database related questions on the test.

Before the practical test, I started studying SQL a lot, I did all the questions I could find on the internet and was fairly confident. On the day of the practical test, she sent me an email with PDF with the questions.

They told me I had 4 hours to complete those tasks. When I first looked at the questions, I was fairly surprised since I didn't expect the questions to be on this subject. I prepared for SQL. haha I had never programmed Web API before but I had done ASP.NET MVC web applications and knew that we can create API in the controller that can return JSON data which can be consumed by client using AJAX calls.

So, for the first task, I was thinking of using Entity Framework connecting to database file and mapping it to objects but in the second task they mentioned not to use Entity Framework so I had to use something else. At the end, I used XML format for data store because it was easy to hand craft an XML file for debugging purposes.

My Category class looks like this:

[Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)     {         Name = name;         Childs = new List<Category>();     } } 

The whole idea was that I would create category data structure using that class and use XmlSerializer to serialise and deserialise it to and from a file.

After that, I moved on to task 2, which was to create Web API. I had 2 options here, either use Web API project in Visual Studios to create those APIs or use the MVC Controller class to create them. I have never used Web API before and since I only had limited amount of time to complete the task, I decided to go with the second option. Learning to use WebAPI might have taken another hour and I didn't have that much time, but if I was working without the time limit, I would have definitely gone the WebAPI route.

Here are my API functions that client can consume. I kept it all in HomeContoller.cs file:

public class HomeController : Controller {     //Index view, pretty simple one     public ActionResult Index()     {         return View();     }      //API that refreshes the category structure, created this just for debugging     public void RefreshStructure()     {         Category category = new Category("root");         category.Childs.Add(new Category("English"));         category.Childs.Add(new Category("History"));         category.Childs.Add(new Category("Science"));         category.Childs.ElementAt(0).Childs.Add(new Category("Literature"));         category.Childs.ElementAt(0).Childs.Add(new Category("Language"));         category.Childs.ElementAt(2).Childs.Add(new Category("Biology"));         category.Childs.ElementAt(2).Childs.Add(new Category("Chemistry"));         category.Childs.ElementAt(2).Childs.Add(new Category("Physics"));         saveAllCategories(category);     }      //Creates root category from XML file     private Category getAllCategories()     {         XmlSerializer xmlS = new XmlSerializer(typeof(Category));         FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open, FileAccess.Read, FileShare.Read);         Category category = (Category)xmlS.Deserialize(readFileStream);         readFileStream.Close();         return category;     }      //Save Categories to XML file     private void saveAllCategories(Category categories)     {         XmlSerializer xmlS = new XmlSerializer(typeof(Category));         TextWriter textWriter = new StreamWriter(Server.MapPath("~/datamodel/model.xml"));         xmlS.Serialize(textWriter, categories);         textWriter.Close();     }      //Navigates to particulate category     private Category navigateToCategory(IEnumerable<string> path, Category root)     {         Category destination = root;          if (path.Count() == 1)  //It has got to be the root         {             return root;         }         else         {             for (int i = 1; i < path.Count(); ++i)             {                 destination = destination.Childs.FirstOrDefault(c => c.Name == path.ElementAt(i));                 if (destination == null)    //Opps that is a problem, path doesn't exist                 {                     return null;                 }             }         }         return destination;     }      //Creates ouput that can be sent as Json. Categories name separated by ~     private string getDelimiterSeparatedCategories(Category category)     {         string retVal = category.Name;         foreach (var c in category.Childs)         {             retVal += "~" + c.Name;         }         return retVal;     }      //API to create Category     [HttpPost]     public JsonResult CreateCategory(IEnumerable<string> path, string name)     {         Category root = getAllCategories();         Category destination = navigateToCategory(path, root);         if (destination == null)         {             return Json(new { Result = "ERROR" });         }          destination.Childs.Add(new Category(name));         string retVal = getDelimiterSeparatedCategories(destination);         saveAllCategories(root);         return Json(new { Result = "OK", Data =  retVal});     }      //API to retrieve category     [HttpPost]     public JsonResult RetrieveCategories(IEnumerable<string> path)     {         Category root = getAllCategories();         Category destination = navigateToCategory(path, root);         if (destination == null)         {             return Json(new { Result = "ERROR" });         }          string retVal = getDelimiterSeparatedCategories(destination);         return Json(new { Result = "OK", Data = retVal });     }      //API to update category     [HttpPost]     public JsonResult UpdateCategory(IEnumerable<string> path, string name)     {         if (path.Count() == 1)         {             return Json(new { Result = "ERROR" });         }          Category root = getAllCategories();         Category destination = navigateToCategory(path, root);         if (destination == null)         {             return Json(new { Result = "ERROR" });         }          destination.Name = name;         string retVal = getDelimiterSeparatedCategories(destination);         saveAllCategories(root);         return Json(new { Result = "OK", Data = retVal });     }      //API to delete category     [HttpPost]     public JsonResult DeleteCategory(IEnumerable<string> path)     {         if (path.Count() == 1)         {             return Json(new { Result = "ERROR" });         }          List<string> pathParent = new List<string>();          for (int i = 0; i < path.Count() - 1; ++i)         {             pathParent.Add(path.ElementAt(i));         }          Category root = getAllCategories();         Category parent = navigateToCategory(pathParent.AsEnumerable(), root);         Category destination = navigateToCategory(path, root);          if (destination == null)         {             return Json(new { Result = "ERROR" });         }          parent.Childs.Remove(destination);         saveAllCategories(root);         string retVal = getDelimiterSeparatedCategories(parent);         return Json(new { Result = "OK", Data = retVal });     } } 

As you can see, I have 4 API exposed for client to consume:

  • CreateCategory
  • RetrieveCategories
  • UpdateCategory
  • DeleteCategory

After finishing those, I went on to create the client that could consume those APIs:

@{     ViewBag.Title = "Home Page"; }  <h1 id="CurrentCategory"></h1>  <div id="CategoriesList"></div>  <input type="text" placeholder="Add Category" id="CategoryName" /><button onclick="addCategory()">Add Category</button><br /> <input type="text" placeholder="Update Category" id="NewName" /><button onclick="updateCategory()">Update Category</button><br /> <button onclick="deleteCategory()">Delete Category</button>  @section scripts { <script type="text/javascript">     var cList = document.getElementById("CategoriesList");     var cCategory = document.getElementById("CurrentCategory")     var pArray = new Array();     pArray[0] = "root";     retrieveCategories();      function retrieveCategories() {         $.ajax({             url: '@Url.Action("RetrieveCategories", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray },             success: function (data) {                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href=\"javascript:gotoParticularCategories('" + categories[i] + "')\">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     }      function getCategoriesList(input) {         var retVal = input.split("~");         return retVal;     }      function gotoParticularCategories(category) {         pArray[pArray.length] = category;         retrieveCategories();     }      function deleteCategory() {         $.ajax({             url: '@Url.Action("DeleteCategory", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray },             success: function (data) {                 if (data.Result != "ERROR") {                     pArray.splice(pArray.length - 1, 1);                 }                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href=\"javascript:gotoParticularCategories('" + categories[i] + "')\">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     }      function addCategory() {         var categoryName = document.getElementById("CategoryName").value;         $.ajax({             url: '@Url.Action("CreateCategory", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray, name: categoryName },             success: function (data) {                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href=\"javascript:gotoParticularCategories('" + categories[i] + "')\">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     }      function updateCategory() {         var categoryName = document.getElementById("NewName").value;         $.ajax({             url: '@Url.Action("UpdateCategory", "Home")',             type: 'POST',             datatype: 'json',             data: { path: pArray, name: categoryName },             success: function (data) {                 var categories = getCategoriesList(data.Data);                 var list = "<ul>";                 cCategory.innerHTML = categories[0];                 for (var i = 1; i < categories.length; ++i) {                     list += "<li><a href=\"javascript:gotoParticularCategories('" + categories[i] + "')\">" + categories[i] + "</a></li>";                 }                 list += "</ul>";                 cList.innerHTML = list;             },             error: function () {                 cList.innerHTML = "There was an error! Please refresh the page";             }         });     } </script>     } 

I know my code could have been structured so much better but I was really trying to finish this in time and if I had time I would have refactored it so it looked much better. For the client I am using AJAX calls to call the APIs I had created before.

At the end, I had a functional web application that did everything they asked for and I sent it to them on time, but I am concerned that it might not have been enough. I feel like I could have done a lot better and I am really passionate about programming and really want this internship. It's been 2 days already and they haven't contacted me and I am really stressed out.

I just wanted to ask if you think I did enough to pass through it or not.

If you want to download the project and play around with it, it's here.

           

Lista de respuestas

3
 
vote
  [Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)     {         Name = name;         Childs = new List<Category>();     } }   

El encadenamiento constructor es su amigo que lo ayuda a reducir la complejidad y (generalmente) la cantidad de código.

  [Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)         : this()     {         Name = name;     } }     

Pero, además, debe preguntarse, ¿realmente quiero que alguna persona que llama establezca la propiedad 9988776665544332 o sería suficiente para acceder / cambiar / eliminar los elementos de ese List<T> . Si este último es suficiente, haz que el setter 9988776655544334 .


homeController

  //Creates root category from XML file private Category getAllCategories() {     XmlSerializer xmlS = new XmlSerializer(typeof(Category));     FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open,  FileAccess.Read, FileShare.Read);     Category category = (Category)xmlS.Deserialize(readFileStream);     readFileStream.Close();     return category; }   
  • El FileStream Implementa IDisposable Por lo tanto, se debe incluir en un bloque using que se ocupa de eliminar el FileStream objeto y para fijarse en la corriente subyacente.

  • ¿Qué sucede si el archivo no existe? Debe encerrarlo en un [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 0 .


  [Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)         : this()     {         Name = name;     } }   1  

El [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 2 Implementa la interfaz [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 3 también.


  [Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)         : this()     {         Name = name;     } }   4  

El [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 5 es redundante, ya que no se alcanzará si [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 6 .

Si almacena el resultado de [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 7 en una variable, se puede reutilizar, en este momento, calcula esto para cada elemento en el [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 8 . Si ese [Serializable] public class Category { public string Name { get; set; } public List<Category> Childs { get; set; } public Category() { Childs = new List<Category>(); } public Category(string name) : this() { Name = name; } } 9 sería algún tipo de Childs0 que no haría tanto daño, solo un elenco y acceder a la propiedad 998877776655443321 , pero para Cualquier otro tipo subyacente, tendría que iterar sobre los artículos completos y contarlos.


  Childs2  

Nunca use la concatenación de cadena dentro de un bucle, eso es para qué es para hacerlo un Childs3

Si anularía el método Childs6655443324 Childs5 clase, así

  Childs6  

Podría aprovechar el Childs7 método como SO

  Childs8  

  Childs9  

No entiendo por qué tiene este List<T>0 allí. Una forma mucho mejor sería usar el método 99887766654433331 . Otra cosa a mencionar es que debe recuperar el 99887766655443332 Después de que haya marcado el List<T>3 Contra List<T>4 . Si List<T>5 es List<T>6 No hay razón para recuperar el List<T>7 .

  List<T>8  

Como nota lateral, debido a List<T>9 Implementa private0 No es necesario llamar private1 En un código Si necesita un 99887766555443343 .


estilo

  • No me gusta el private4 Carcasa para nombrar private5 Metodos. ¿Por qué querría distinguir entre private6 y private7 por el estilo de la carcasa? Si posteriormente decide cambiar un método 998877666554433348 a private9 , es probable que se olvide de cambiar el nombre del método.

  • Los comentarios anteriores de los métodos como //Creates root category from XML file private Category getAllCategories() { XmlSerializer xmlS = new XmlSerializer(typeof(Category)); FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open, FileAccess.Read, FileShare.Read); Category category = (Category)xmlS.Deserialize(readFileStream); readFileStream.Close(); return category; } 0 No agregue ningún valor. Si usted tendría una documentación XML adecuada, esto también se presentaría en IntelliSense. Dicho esto, para //Creates root category from XML file private Category getAllCategories() { XmlSerializer xmlS = new XmlSerializer(typeof(Category)); FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open, FileAccess.Read, FileShare.Read); Category category = (Category)xmlS.Deserialize(readFileStream); readFileStream.Close(); return category; } 1 Métodos que forman parte de un 99887776655443352 La documentación XML adecuada es una necesidad.

  • Usted está utilizando llaves //Creates root category from XML file private Category getAllCategories() { XmlSerializer xmlS = new XmlSerializer(typeof(Category)); FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open, FileAccess.Read, FileShare.Read); Category category = (Category)xmlS.Deserialize(readFileStream); readFileStream.Close(); return category; } 3 aunque pueden ser opcionales, que es bueno .

  • Debería considerar cambiar algunos nombres de métodos; e.g

      //Creates root category from XML file private Category getAllCategories() {     XmlSerializer xmlS = new XmlSerializer(typeof(Category));     FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open,  FileAccess.Read, FileShare.Read);     Category category = (Category)xmlS.Deserialize(readFileStream);     readFileStream.Close();     return category; } 4  

    es simplemente engañoso. Tal vez //Creates root category from XML file private Category getAllCategories() { XmlSerializer xmlS = new XmlSerializer(typeof(Category)); FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open, FileAccess.Read, FileShare.Read); Category category = (Category)xmlS.Deserialize(readFileStream); readFileStream.Close(); return category; } 5 sería un nombre mejor.

 
[Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)     {         Name = name;         Childs = new List<Category>();     } } 

Constructor chaining is your friend which helps you to reduce complexity and (usually) the amount of code.

[Serializable] public class Category {     public string Name { get; set; }     public List<Category> Childs { get; set; }      public Category()     {         Childs = new List<Category>();     }      public Category(string name)         : this()     {         Name = name;     } }   

but moreover you should ask yourself, do I really want any outside caller to set the Childs property or would it be enough to access/change/delete the items of that List<T>. If the latter is enough, make the setter private.


HomeController

//Creates root category from XML file private Category getAllCategories() {     XmlSerializer xmlS = new XmlSerializer(typeof(Category));     FileStream readFileStream = new FileStream(Server.MapPath("~/datamodel/model.xml"), FileMode.Open,  FileAccess.Read, FileShare.Read);     Category category = (Category)xmlS.Deserialize(readFileStream);     readFileStream.Close();     return category; } 
  • The FileStream implements IDisposable hence it should be enclosed in a using block which takes care of disposing the FileStream object and therefor closing the underlying stream.

  • What happens if the file doesn't exist ? You should enclose it in a try..catch.


private void saveAllCategories(Category categories) {     XmlSerializer xmlS = new XmlSerializer(typeof(Category));     TextWriter textWriter = new StreamWriter(Server.MapPath("~/datamodel/model.xml"));     xmlS.Serialize(textWriter, categories);     textWriter.Close(); } 

The TextWriter implements the IDisposable interface as well.


//Navigates to particulate category private Category navigateToCategory(IEnumerable<string> path, Category root) {     Category destination = root;      if (path.Count() == 1)  //It has got to be the root     {         return root;     }     else     {         for (int i = 1; i < path.Count(); ++i)         {             destination = destination.Childs.FirstOrDefault(c => c.Name == path.ElementAt(i));             if (destination == null)    //Opps that is a problem, path doesn't exist             {                 return null;             }         }     }     return destination; }   

The else is redundant, because it won't be reached if path.Count() == 1.

If you store the result of path.Count() into a variable it can be reused, right now you calculate this for each item in the IEnumerable<T>. If that IEnumerable<T> would be some type of ICollection<T> that wouldn't do that much harm, just a cast and accessing the Count property, but for any other underlying type, it would need to iterate over the whole items and count them.


//Creates ouput that can be sent as Json. Categories name separated by ~ private string getDelimiterSeparatedCategories(Category category) {     string retVal = category.Name;     foreach (var c in category.Childs)     {         retVal += "~" + c.Name;     }     return retVal; }   

Never ever use string concatenation within a loop, thats what a StringBuilder is for.

If you would override the ToString() method of the Category class like so

public override string ToString() {     return Name; }   

you could take advantage of the string.Join() method like so

private string getDelimiterSeparatedCategories(Category category) {     return category.Name + "~" + string.Join("~", category.Childs); }   

//API to delete category [HttpPost] public JsonResult DeleteCategory(IEnumerable<string> path) {     if (path.Count() == 1)     {         return Json(new { Result = "ERROR" });     }      List<string> pathParent = new List<string>();      for (int i = 0; i < path.Count() - 1; ++i)     {         pathParent.Add(path.ElementAt(i));     }      Category root = getAllCategories();     Category parent = navigateToCategory(pathParent.AsEnumerable(), root);     Category destination = navigateToCategory(path, root);      if (destination == null)     {         return Json(new { Result = "ERROR" });     }      parent.Childs.Remove(destination);     saveAllCategories(root);     string retVal = getDelimiterSeparatedCategories(parent);     return Json(new { Result = "OK", Data = retVal }); } 

I don't get why you have this List<string> pathParent in there. A much better way would be to use the Take() extension method. Another thing to mention is that you should retrieve the parent after you have checked the destination against null. If destination is null then there is no reason to retrieve the parent.

//API to delete category [HttpPost] public JsonResult DeleteCategory(IEnumerable<string> path) {     int pathCount = path.Count();      if (pathCount == 1)     {         return Json(new { Result = "ERROR" });     }      Category root = getAllCategories();      Category destination = navigateToCategory(path, root);      if (destination == null)     {         return Json(new { Result = "ERROR" });     }      Category parent = navigateToCategory(path.Take(pathCount - 1), root);      parent.Childs.Remove(destination);      saveAllCategories(root);     string retVal = getDelimiterSeparatedCategories(parent);      return Json(new { Result = "OK", Data = retVal }); } 

As a side note, because List<T> implements IEnumerable<T> there is no need to call AsEnumerable() on such a List<T> if you need an IEnumerable<T>.


Style

  • I don't like the camelCase casing for naming private methods. Why would you want to distinguish between private and public by the casing style? If you later decide to change a private method to public you will likely forget to rename the method.

  • The comments above the methods like //Navigates to particulate category don't add any value. If you would have proper xml documentation this would also show up in intellisense. That being said, for public methods which are part of an API proper xml documentation is a must-have.

  • you are using braces {} although they might be optional which is good.

  • you should consider to change some method names; e.g

    Category root = getAllCategories();   

    is just misleading. Maybe GetRootCategory would be a better name.

 
 
 
 

Relacionados problema

9  Proporcionando interfaces de "envoltura" sin marcar para una API con excepciones verificadas  ( Providing unchecked exception wrapper interfaces for an api with checked excep ) 
Bloqueado . Esta pregunta y sus respuestas son bloqueadas porque la pregunta es off-topic pero tiene importancia histórica. Actualmente no está a...

8  Implementación de la API de Django  ( Django api implementation ) 
Estoy construyendo un backend a una aplicación móvil que se alojará en un sitio de Django conectado a una base de datos PostgreSQL. Nunca he construido nada...

2  Objeto de búsqueda de la base de datos, o fetchlo usando una API si no está ahí  ( Fetch object from database or fetch it using an api if it isnt there ) 
Para dar algunos antecedentes en este código en particular, hay un controlador que recibe un objeto, las partes de los hashes y se analiza en una base de dato...

2  Punteros para el formato de encabezado, diseño y diseño de la biblioteca de la biblioteca C ++ / CLI  ( Pointers for c cli library header formatting layout and design ) 
He diseñado una biblioteca de Wrapper C ++ / CLI que permite aplicaciones C ++ en Windows, y otras plataformas que pueden cargar C DLLs (por ejemplo, Java a t...

3  Biblioteca de Wrapper Perl (escrito usando Moose) para una API de descanso  ( Perl wrapper library written using moose for a rest api ) 
Escribí una biblioteca de envoltura para una API de descanso en Perl usando la Biblioteca Moose. Me gustaría reunir algunos comentarios sobre ella (principalm...

3  Prueba de un controlador API de rieles  ( Testing a rails api controller ) 
Estoy construyendo una API de JSON. Estoy escribiendo mis pruebas de controlador para que comparen el organismo de respuesta al JSON real, estoy generando en ...

4  Diseño de la API de inyección de dependencia de Backbone.js  ( Backbone js dependency injection api design ) 
Estoy escribiendo un complemento de inyección de dependencia para la Backbone JavaScript Framework, y no estoy seguro de cuál es la API Para el argumento co...

2  Este código frágil ODATA a SQL Server C # no es sostenible con el tiempo  ( This brittle odata to sql server c code isnt sustainable over time ) 
La intención de este código es acceder a una API de ODATA de terceros para capturar solo los datos relevantes a un conjunto interno existente de tablas de ser...

10  Implementación de Linq-To-Sage  ( Linq to sage implementation ) 
seguimiento de mi Última pregunta donde envié la API de SAITE con un 9988776665544334 < / Código> Interfaz, decidí empujar la abstracción un paso más allá,...

11  Proveedor de formato de fecha  ( Date format provider ) 
Estoy enfrentando un problema con una API para manejar las fechas en Java. No soy un programador muy experimentado y mi inglés es muy malo. Problema Estoy...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos