티스토리 뷰

반응형

PCLSample 솔루션에 WebAPI를 이용해서 CRUD 하는 셈플을 완성했다. (옛날에는 무지 쉽게 했었는데..으흠;;)

이번 솔루션은 단순히 CRUD 오퍼레이션을 하는 것이 아니라, Repository pattern을 이용하도록 만들었다. 거의 실사용하는 수준으로 만들어져있는 부분들이 있으니 잘 참고 하면 간단한 서비스는 쉽게 만들 것이라 생각한다.

 

1. PCLSample.DAL

 

* PersonModelMap.cs

Id필드에 Identity속성 추가 - 속성이 추가 되기 위해서는 PCLSample 데이터베이스를 삭제 하고 다시 실행해야 적용된다.

    class PersonModelMap : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<PersonModel>
    {
        public PersonModelMap()
        {
            this.HasKey(f => f.Id);

            this.ToTable("People");

            this.Property(f => f.Id)
                .IsRequired()
                .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)
                .HasColumnName("Id");
            this.Property(f => f.Name)
                .HasMaxLength(50)
                .HasColumnName("Name");
            this.Property(f => f.Age)
                .HasColumnName("Age");
            this.Property(f => f.Sex)
                .HasColumnName("Sex");
        }
    }

 

* GenericRepository.cs

Update를 호출할 때 key를 함께 넘겨주어 처리하도록 수정

 

        /// <summary>
        /// Entity를 받아서 수정
        /// </summary>
        /// <param name="entityToUpdate"></param>
        public virtual void Update(TEntity entityToUpdate, object key = null)
        {
            var entry = _context.Entry(entityToUpdate);
            if(key ==  null)
                key = this.GetPrimaryKey(entry);

            if (entry.State == EntityState.Detached)
            {
                var currentEntry = _dbSet.Find(key);
                if (currentEntry != null)
                {
                    var attachedEntry = _context.Entry(currentEntry);
                    attachedEntry.CurrentValues.SetValues(entityToUpdate);
                }
                else
                {
                    _dbSet.Attach(entityToUpdate);
                    entry.State = EntityState.Modified;
                }

            }
        }

 

구글에서 찾아서 추가를 했는데..실제로 동작은 않되는 것 같다.

        private object GetPrimaryKey(DbEntityEntry entry)
        {
            var myObject = entry.Entity;
            var property = myObject.GetType()
                             .GetProperties()
                             .FirstOrDefault(prop => Attribute.IsDefined(prop, typeof(KeyAttribute)));
            if (property == null)
                return null;
            return property.GetValue(myObject, null);
        }

* IGenericRepository.cs

    public interface IGenericRepository<TEntity>
     where TEntity : class
    {
        System.Linq.IQueryable<TEntity> AllGetting();
        void Delete(object id);
        void Delete(TEntity entityToDelete);
        void Detach(TEntity entityToDetach);
        void Dispose();
        System.Linq.IQueryable<TEntity> Getting(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null, Func<System.Linq.IQueryable<TEntity>, System.Linq.IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "", int? page = null, int? pageSize = null);
        TEntity GettingByID(object id);
        void Insert(TEntity entity);
        void Update(TEntity entityToUpdate, object key = null);
    }

 

2. PCLSample.WebAPI

StartPage.html을 하나 추가해서, 시작페이지로 지정했다. 아무래도 뭔가 나오는 것이 좋다.

 

* PeopleController.cs

Repository pattern을 사용하는 컨트롤러는 자동생성이 않되기 때문에 수동으로 작업해 준다.

 

    public class PeopleController : ApiController
    {
        private IUnitOfWork _uow;

        public PeopleController()
        {
            _uow = GlobalVariables.Container.Resolve<IUnitOfWork>();
        }

        /// <summary>
        /// 조회 여러개
        /// </summary>
        /// <returns></returns>
        [Queryable]
        public IQueryable<PersonModel> GetPeople()
        {
            return _uow.PeopleRepo.AllGetting();
        }

        /// <summary>
        /// 조회 1개
        /// </summary>
        public PersonModel GetPeople(int Id)
        {
            return _uow.PeopleRepo.GettingByID(Id);
        }

        /// <summary>
        /// 수정
        /// </summary>
        /// <param name="id"></param>
        /// <param name="person"></param>
        /// <returns></returns>
        public HttpResponseMessage PutPeople(int id, PersonModel person)
        {
            if (ModelState.IsValid && id == person.Id)
            {
                _uow.PeopleRepo.Update(person, id);
                _uow.Save();

                return Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        /// <summary>
        /// 등록
        /// </summary>
        /// <param name="person"></param>
        /// <returns></returns>
        public HttpResponseMessage PostPeople(PersonModel person)
        {
            if (ModelState.IsValid)
            {
                _uow.PeopleRepo.Insert(person);
                _uow.Save();
                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, person);
                response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = person.Id }));
                return response;
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        /// <summary>
        /// 삭제
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public HttpResponseMessage DeletePeople(int id)
        {
            var existItem = _uow.PeopleRepo.GettingByID(id);
            if (existItem == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            _uow.PeopleRepo.Delete(existItem);
            _uow.Save();

            return Request.CreateResponse(HttpStatusCode.OK, existItem);
        }
    }

 

 

3. PCLSample.PCL

 

* WebAPIBase.cs

 

    public abstract class WebAPIBase<T> : BindableBase
    {
        /// <summary>
        /// 베이스Uri
        /// </summary>
        public string BaseUri { get; set; }

        /// <summary>
        /// 서비스 Uri
        /// </summary>
        public string ServiceUri { get; set; }

        /// <summary>
        /// 결과코드
        /// </summary>
        public string ResultCode { get; set; }

        /// <summary>
        /// 결과메시지
        /// </summary>
        public string ResultMsg { get; set; }

        /// <summary>
        /// 반환갯수
        /// </summary>
        protected int NumOfRows { get; set; }

        private int pageNo;
        /// <summary>
        /// 페이지 번호
        /// </summary>
        public int PageNo
        {
            get { return pageNo; }
            set
            {
                pageNo = value;
                OnPropertyChanged();
            }
        }

        private int totalCount;
        /// <summary>
        /// 전체 카운트
        /// </summary>
        public int TotalCount
        {
            get { return totalCount; }
            set
            {
                totalCount = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// 토탈 페이지 = totalCount / NumOfRows + 1
        /// </summary>
        public int TotalPage { get; set; }

        private bool isBusy;
        /// <summary>
        /// 작업중 여부
        /// </summary>
        public bool IsBusy
        {
            get { return isBusy; }
            set { isBusy = value; OnPropertyChanged(); }
        }

        /// <summary>
        /// 생성자
        /// </summary>
        public WebAPIBase()
        {
            BaseUri = "";
            ServiceUri = "";
            NumOfRows = 30;
            PageNo = 1;

            this.PropertyChanged +=
                (s, e) =>
                {
                    switch (e.PropertyName)
                    {
                        case "NumOfRows":
                        case "TotalCount":
                            if (TotalCount > 0 && NumOfRows > 0)
                            {
                                TotalPage = TotalCount / NumOfRows;
                                if ((TotalCount % NumOfRows) > 0)
                                    TotalPage++;
                            }
                            else
                            {
                                TotalPage = 0;
                            }
                            break;
                    }
                };
        }

        /// <summary>
        /// 조회
        /// </summary>
        public async Task<string> GetData(string requestUri)
        {
            string result = string.Empty;
            IsBusy = true;

            using (HttpClient hc = new HttpClient())
            {
                try
                {
                    //타임아웃30초
                    hc.Timeout = new TimeSpan(0, 0, 30);
                    var uri = string.Format("{0}{1}{2}", BaseUri, ServiceUri, requestUri);
                    result = await hc.GetStringAsync(uri);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    IsBusy = false;
                }
            }
            IsBusy = false;
            return result;
        }

 

        /// <summary>
        /// 조회 목록
        /// </summary>
        public async Task<IList<T>> GetDatas(string requestUri)
        {
            IList<T> returnValue = new List<T>();
            IsBusy = true;

            using (HttpClient hc = new HttpClient())
            {
                try
                {
                    hc.Timeout = new TimeSpan(0, 0, 30);
                    var uri = string.Format("{0}{1}{2}", BaseUri, ServiceUri, requestUri);
                    var result = await hc.GetAsync(uri);
                    if (result.IsSuccessStatusCode == true)
                    {
                        var data = await result.Content.ReadAsStringAsync();
                        if (data != null)
                        {
                            returnValue = JsonConvert.DeserializeObject<List<T>>(data);
                        }
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    IsBusy = false;
                }
            }
            IsBusy = false;
            return returnValue;
        }

 

        /// <summary>
        /// 등록
        /// </summary>
        /// <param name="postItem"></param>
        /// <returns></returns>
        public virtual async Task<T> PostAsync(T postItem)
        {
            T returnValue = default(T);
            if (postItem != null)
            {
                var json = JsonConvert.SerializeObject(postItem);
                if (json != null && json.Length > 0)
                {
                    using (var hc = new HttpClient())
                    {
                        var sc = new StringContent(json, Encoding.UTF8, "application/json");
                        try
                        {
                            var uri = string.Format("{0}{1}", BaseUri, ServiceUri);
                            var resp = await hc.PostAsync(uri, sc);
                            if (resp.IsSuccessStatusCode == true)
                            {
                                var content = await resp.Content.ReadAsStringAsync();
                                returnValue = JsonConvert.DeserializeObject<T>(content);
                            }
                        }
                        catch (Exception ex)
                        {
#if DEBUG
                            System.Diagnostics.Debug.WriteLine(ex.Message);
                            throw;
#endif
                        }
                    }
                }
            }
            return returnValue;
        }

 

        /// <summary>
        /// 수정
        /// </summary>
        /// <param name="putItem"></param>
        /// <returns></returns>
        public virtual async Task<bool> PutAsync(T putItem, object key)
        {
            bool returnValue = false;

            var json = JsonConvert.SerializeObject(putItem);
            if (json != null && json.Length > 0)
            {
                using (var hc = new HttpClient())
                {
                    var sc = new StringContent(json, Encoding.UTF8, "application/json");
                    var uri = string.Format("{0}{1}{2}", BaseUri, ServiceUri, key.ToString());
                    try
                    {
                        var resp = await hc.PutAsync(uri, sc);
                        if (resp.IsSuccessStatusCode == true)
                        {
                            returnValue = true;
                        }
                    }
                    catch (Exception ex)
                    {
#if DEBUG
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                        throw;
#endif
                    }
                }
            }
            return returnValue;

        }

 

        /// <summary>
        /// 삭제
        /// </summary>
        /// <param name="deleteItem"></param>
        /// <returns></returns>
        public virtual async Task<bool> DeleteAsync(T deleteItem, object key)
        {
            bool returnValue = false;

            using (var hc = new HttpClient())
            {
                var query = string.Format("{0}{1}{2}", BaseUri, ServiceUri, key.ToString());
                try
                {
                    var resp = await hc.DeleteAsync(query);
                    if (resp.IsSuccessStatusCode)
                    {
                        returnValue = true;
                    }
                }
                catch (Exception ex)
                {
#if DEBUG
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    throw;
#endif
                }
            }
            return returnValue;
        }

    }

 

* PersonHelper.cs

 

    public class PersonHelper : WebAPIBase<PersonModel>
    {
        /// <summary>
        /// 인스턴스
        /// </summary>
        private readonly static PersonHelper instance = new PersonHelper();

        /// <summary>
        /// 인스턴스 프로퍼티
        /// </summary>
        public static PersonHelper Instance
        {
            get
            {
                return instance;
            }
        }
       
        /// <summary>
        /// 생성자
        /// </summary>
        public PersonHelper()
            : base()
        {
            BaseUri = "http://localhost:59409";
            ServiceUri = "/api/People/";

        }

    }

 

* MainViewModel.cs

 

        private DelegateCommand _getListCommand;
        public DelegateCommand GetListCommand
        {
            get
            {
                return _getListCommand = _getListCommand ?? new DelegateCommand(
                    async para =>
                    {
                        var result = await PersonHelper.Instance.GetDatas("");
                        People = new ObservableCollection<PersonModel>(result);
                    });
            }
        }
        private DelegateCommand _newCommand;
        public DelegateCommand NewCommand
        {
            get
            {
                return _newCommand = _newCommand ?? new DelegateCommand(
                    para =>
                    {
                        Person = new PersonModel();
                        People.Add(Person);
                    });
            }
        }

        private DelegateCommand _updateCommand;
        public DelegateCommand UpdateCommand
        {
            get
            {
                return _updateCommand = _updateCommand ?? new DelegateCommand(
                    async para =>
                    {
                        if (Person == null) return;

                        if (Person.Id == 0)
                        {
                            var newPerson = await PersonHelper.Instance.PostAsync(Person);
                            Person.Id = newPerson.Id;
                        }
                        else
                        {
                            var update = await PersonHelper.Instance.PutAsync(Person, Person.Id);
                        }
                    });
            }
        }

        private DelegateCommand _deleteCommand;
        public DelegateCommand DeleteCommand
        {
            get
            {
                return _deleteCommand = _deleteCommand ?? new DelegateCommand(
                    async para =>
                    {
                        if (Person != null)
                        {
                            var result = await PersonHelper.Instance.DeleteAsync(Person, Person.Id);
                            if (result == true)
                            {
                                People.Remove(Person);
                                Person = null;
                            }
                        }
                    });
            }
        }

4. PCLSample.WPF

 

2군데 수정

* MainWindow.xaml, MainWindow.xaml.cs

 

실버라이트 프로젝트와 Store app 프로젝트는 직접 수정하도록 한다.

 

5. 솔루션 프로퍼티에서 시작 프로젝트를 2개로 지정한다.

 

F5로 실행하면 아래와 같이 2개의 창이 뜬다.

 

 

 

6. 오퍼레이션

 

 

 

 

Id 5번을 선택 한 후

Name : kaki110, Age : 30으로 수정 후 Update

 

 

 

New 클릭 -> Name : kaki120, Age : 33, Sex : uncheck -> Update 클릭

 

 

Id 3번 선택 후 Delete를 클릭

 

 

 

전체 소스

http://sdrv.ms/1cBaryF

 

반응형
댓글