티스토리 뷰

반응형

어제 post man으로 테스트했던 내용을 1시간 30분만에 universal sample에 상쾌하게 코딩을 완료했다. 물론 정리가 완전하게 된 코딩은 아니다. 정리하기전 코딩으로 포스트 한다. 하지만, 난 정말 PCL로 정리된 소스가 필요해!!! 라고 생각 한다면, 앱 개발 페이스 북 그룹에 가입하면 Git에서 관리하는 소스 코드를 볼 수 있을 것이다.

비록, 비공개 그룹이기는 하지만, 가입에 특별한 제한은 없으니 관심있는 분은 가입하도록 한다.

 

윈도우 & 윈도우폰 앱 개발 모임

https://www.facebook.com/groups/vapps/

간단히 소개 하자면, 냄새 풀풀나는 남자 개발자들이 대부분 득실거린다. 모임 후기 링크를 추가로 올릴까 생각하고 찾아봤더니, 이상한 사람이 서있는 사진이 있어서 포기한다. ㅡㅡ;;

 

전체 소스는 맨 아래 추가하였다.

 

"모임 후기 링크 올리지?"

 

"싫다"

"인터넷에 이상하게 나온 내 사진이 돌아다니는 것을 원치 않는다."

 

"Source가 이상한데, Target이 좋을리 없잔아?"

 

"......"

 

 

1. 기본 소스

UniversalSample 소스

 

2. BitlyHelper.cs

 

중요한 부분을 먼저 설명하겠다.

 

        /// <summary>
        /// Bitly 인증
        /// </summary>
        /// <param name="id"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public async Task<bool> BitlyAuthAsync(string id, string password)
        {
            var con = string.Format("grant_type=password&username={0}&password={1}", id, password);
            var content = new StringContent(con, Encoding.UTF8, "application/x-www-form-urlencoded");

            var hc = new HttpClient();
            hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "ZDdiZTg1ZTYyZGZhNjE2YjllY2UwNWU5YjJkOTYzODQwNzI0ODEyMTo1OTE2MjIxNjViZDhkMmU3MDI4YmMwYjBjN2VmYTQ2OWVkY2NjZTYy");
            var result = await hc.PostAsync("https://api-ssl.bitly.com/oauth/access_token", content);
            if (result == null) return false;

            var jobj = JsonConvert.DeserializeObject<JObject>(await result.Content.ReadAsStringAsync());
            if (jobj == null) return false;

            _accessToken = jobj["access_token"].ToString();

            return true;
        }

 

HttpClient를 이용해서 PostAsync 메소드를 이용하기 위해서는 HttpContent가 필요한데 그 중에 하나가 StringContent이다.

con에는 사용자 아이디와 비밀번호를 파라메터로 받아서 넣어준다.

 

var con = string.Format("grant_type=password&username={0}&password={1}", id, password);

var content = new StringContent(con, Encoding.UTF8, "application/x-www-form-urlencoded");

 

 

hc헤더에 Authorization을 넣기 위해서는 new AuthenticationHeaderValue를 이용해서 생성한 후 사용한다. 그런데, 여기서 ZDdiZ...이 부분을 어떻게 만드는지 설명을 하고 넘어가야 하지 않을까 한다.

 

hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "ZDdiZTg1ZTYyZGZhNjE2YjllY2UwNWU5YjJkOTYzODQwNzI0ODEyMTo1OTE2MjIxNjViZDhkMmU3MDI4YmMwYjBjN2VmYTQ2OWVkY2NjZTYy");

 

 

이전 포스트를 보면 Client ID와 Client Secret가 있었던것을 기억할 것이다. 기억이 나지 않으면 http://kaki104.tistory.com/248 링크를 눌러서 다시 본다.

 

이 두개를 Client ID + ":" + Client Secret를 해서 하나의 문자열로 구성한 후 http://www.base64encode.org/ 사이트로 이동 후 상단에 문자열을 붙여 넣고, Encode버튼을 눌러주면 만들어지는 문자열이다.

API Document에는

Where Authorization: is set to "Basic " + base64encode(client_id + ":" + client_secret). An example response might look like

위와 같이 표시되어있다. 변환된 문자열이 위와 다르기는 하지만 위에 것도 인증이 되는 것을 확인했다.

 

 

"광고닷!"

 

"스크린샷을 만들다 보니 본이 아니게 들어갔다."

 

"포토샵으로 잘라내면 돼잖아?"

 

"귀찮다"

 

ㅡ,.ㅡ 퍽퍽펑!!

 

 

반환된 결과를 JObject로 변환 후 access_token을 찾아서 _accessToken에 넣는다. JObject로 변환해 놓으면 특정 값을 찾을 때 편리하다. 해...보니 OAuth 2.0도 별거 없는것 같다. @,.@

 

var jobj = JsonConvert.DeserializeObject<JObject>(await result.Content.ReadAsStringAsync());
if (jobj == null) return false;

_accessToken = jobj["access_token"].ToString();

 

 

GetShorternUrl 메소드에 대한 설명은 생략한다. 그냥 보면 쉽게 알 수 있을 것이라 생각한다.

 

전체 소스

 

using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace UniversalSample
{
    public class BitlyHelper
    {
        /// <summary>
        /// Access Token
        /// </summary>
        internal string _accessToken ;

        private static BitlyHelper _instance;

        /// <summary>
        /// BitlyHelper Instance
        /// </summary>
        public static BitlyHelper Instance
        {
            get { return _instance = _instance ?? new BitlyHelper(); }
        }

        /// <summary>
        /// Bitly 인증
        /// </summary>
        /// <param name="id"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public async Task<bool> BitlyAuthAsync(string id, string password)
        {
            var con = string.Format("grant_type=password&username={0}&password={1}", id, password);
            var content = new StringContent(con, Encoding.UTF8, "application/x-www-form-urlencoded");

            var hc = new HttpClient();
            hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "ZDdiZTg1ZTYyZGZhNjE2YjllY2UwNWU5YjJkOTYzODQwNzI0ODEyMTo1OTE2MjIxNjViZDhkMmU3MDI4YmMwYjBjN2VmYTQ2OWVkY2NjZTYy");
            //YjA3YjIyYWFlYTVjMWQ2NDJkZTM3ZThlMmIzZjI0OGQ2Y2UyMmVmODoyYmQyZThjODdhMjEwNDM5YmY4NmFlOGQ3ODkyODQ4YWQxNzRmYmEz
            //ZDdiZTg1ZTYyZGZhNjE2YjllY2UwNWU5YjJkOTYzODQwNzI0ODEyMTo1OTE2MjIxNjViZDhkMmU3MDI4YmMwYjBjN2VmYTQ2OWVkY2NjZTYy
            var result = await hc.PostAsync("https://api-ssl.bitly.com/oauth/access_token", content);
            if (result == null) return false;

            var jobj = JsonConvert.DeserializeObject<JObject>(await result.Content.ReadAsStringAsync());
            if (jobj == null) return false;

            _accessToken = jobj["access_token"].ToString();

            return true;
        }

        /// <summary>
        /// Shorten
        /// </summary>
        /// <param name="longUrl"></param>
        /// <returns></returns>
        public async Task<string> GetShortenUrl(string longUrl)
        {
            var returnValue = string.Empty;

            var hc = new HttpClient();
            var uri = string.Format("https://api-ssl.bitly.com/v3/shorten?access_token={0}&longUrl={1}", _accessToken, longUrl);
                //longUrl의 Encode해서 보내야한다

                var encodedUrl = Uri.EscapeDataString(longUrl);
                var uri = string.Format("
https://api-ssl.bitly.com/v3/shorten?access_token={0}&longUrl={1}", _accessToken, encodedUrl);

            var result = await hc.GetStringAsync(uri);
            if (result == null) return returnValue;

            var jobj = JsonConvert.DeserializeObject<JObject>(result);
            if (jobj == null) return returnValue;

            var data = jobj["data"];
            if (data == null) return returnValue;

            returnValue = data["url"].ToString();

            return returnValue;
        }
    }
}

3. MainPageVM.cs

 

추가한 부분에 대한 소스만 올리겠다. 전체 소스는 하단의 전체 소스를 참고한다. 그리고 이곳에 올리지는 않치만 LongUrl 프로퍼티 채인지 이벤트 처리하는 부분을 생성자에 추가해 놓았다. LongUrl프로퍼티가 변경되면 커맨드의 활성/비활성 여부를 변경해 주어야 하기 때문이다.

 

        /// <summary>
        /// Bitly Auth 여부
        /// </summary>
        public bool IsBitlyAuth
        {
            get { return _isBitlyAuth; }
            set { SetProperty(ref _isBitlyAuth, value); }
        }

        /// <summary>
        /// Long Url
        /// </summary>
        public string LongUrl
        {
            get { return _longUrl; }
            set { SetProperty(ref _longUrl, value); }
        }

        /// <summary>
        /// Shorten Url
        /// </summary>
        public string ShortUrl
        {
            get { return _shortUrl; }
            set { SetProperty(ref _shortUrl, value); }
        }

        /// <summary>
        /// BitlyAuth Command
        /// </summary>
        public RelayCommand BitlyAuthCommand
        {
            get
            {
                return _bitlyAuthCommand = _bitlyAuthCommand ?? new RelayCommand(async args =>
                {
                    IsBitlyAuth = await BitlyHelper.Instance.BitlyAuthAsync("kaki104", "zkzlroqkfxptmxm");
                    CheckCommands();
                }, () => !IsBitlyAuth);
            }
        }

        /// <summary>
        /// GetShortenUrl Command
        /// </summary>
        public RelayCommand GetShortenUrlCommand
        {
            get
            {
                return _getShortenUrlCommand = _getShortenUrlCommand ?? new RelayCommand(async args =>
                    {
                        ShortUrl = await BitlyHelper.Instance.GetShortenUrl(LongUrl);
                    }, () => IsBitlyAuth && string.IsNullOrEmpty(LongUrl) == false);
            }
        }

        /// <summary>
        /// 커맨드 활성/비활성 확인
        /// </summary>
        private void CheckCommands()
        {
            BitlyAuthCommand.RaiseCanExecuteChanged();
            GetShortenUrlCommand.RaiseCanExecuteChanged();
        }

 

StackOverflow에서는 글 작성할 때 앞에서 4칸을 띄우면 소스로 인식해서 택스트 박스에 이쁘게 들어가는데, 이넘의 블로그는 그런 기능이 없다. 그나마 다행인 것은 <>를 html로 인식해서 않보이게 하는 것이 없다는 것이다.

 

4. MainPage.xaml

 

추가된 부분에 대한 소스만 올린다.

 

            <HubSection MinWidth="400" Header="Bitly" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
                <DataTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="40"/>
                            <RowDefinition Height="40"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="40"/>
                        </Grid.RowDefinitions>
                        <Button Content="Bitly Auth" Command="{Binding BitlyAuthCommand, Mode=OneWay}" Width="120"/>
                        <Button Grid.Row="1" Content="Shorten Url" Command="{Binding GetShortenUrlCommand, Mode=OneWay}" Width="120"/>
                        <TextBox Grid.Row="2" TextWrapping="Wrap" Text="{Binding LongUrl, Mode=TwoWay}"/>
                        <TextBox Grid.Row="3" Text="{Binding ShortUrl, Mode=OneWay}" IsReadOnly="True"/>

                    </Grid>
                </DataTemplate>
            </HubSection>

 

5. 실행화면

 

음 이미지 추가할 때 매번 느끼는 짜증이 하나 있는데 이미지 사이즈가 커서 오른쪽 끝에 내용이 않보이기 때문에 이미지 너비를 일부러 작게 줄이는데, 사이즈를 입력하고 바로 아래 이미지를 클릭하면 작게 바꾸었던 이미지가 다시 원래 크기로 돌아가는 버그가 있다. 이게 한두장 줄일때는 그냥 그런가 하고 넘어가는데, 매번 이런 식이라... 짬뽕난다. 된장!쌈장!꼬추장!

 

Bitly Auth 버튼 클릭 

 

인증이 완료되면 인증 버튼이 비활성화 된다.

 

url을 입력하고 tab키를 누르면 Shorten url 버튼이 활성화 된다.

 

Shorten Url 버튼을 클릭하면 짧은 url이 하단에 출려된다. 선택 후 마우스 오른쪽 버튼을 눌러서 복사하기를 선택 한다.

 

브라우저 주소창에 붙여 넣기를 하고 엔터를 입력한다.

 

원하는 결과 페이지 출력

 

"위에 이미지 링크 눌러보니 OneDrive 로그인 해야한다고 하는데?"

 

"그렇다"

 

"일부러 그런거야?"

 

"하다보니 그렇게 됐다"

 

"로그인 않해도 볼 수 있는 링크로 바꿔주지?"

 

"귀찮다"

 

"...." 폭폭폭폭 펑~

 

 

"윈폰 화면도 수정 한거야?

 

"직접 수정할 수 있는 기회를 주기 위해 않했다"

 

"귀찮아서 않한거지?"

 

"...음...그렇다"

 

ㅡ,,ㅡ 슈우욱~콰앙앙!!!!

 

 

6. 소스

 

UniversalSample_20140801.zip

 

소스에서 사용한 아이디/비밀번호/Client Id/Client Secret은 자신의 것으로 변경해서 사용하도록 한다. 포스트 등록 후 변경한다.

 

반응형
댓글