diff --git a/servant-csharp.cabal b/servant-csharp.cabal
--- a/servant-csharp.cabal
+++ b/servant-csharp.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                servant-csharp
-version:             0.0.1.0
+version:             0.0.2.0
 synopsis:            Generate servant client library for C#
 description:         Generate servant client library for C#
 homepage:            https://github.com/cutsea110/servant-csharp.git
@@ -18,6 +18,8 @@
 
 library
   exposed-modules:     CS
+                     , CS.Common
+                     , CS.JsonDotNet
   -- other-modules:       
   other-extensions:    OverloadedStrings
                      , ScopedTypeVariables
diff --git a/src/CS/Common.hs b/src/CS/Common.hs
new file mode 100644
--- /dev/null
+++ b/src/CS/Common.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module CS.Common where
+
+import Data.Monoid ((<>))
+import Data.Proxy
+import Data.Text
+import Data.Time (UTCTime)
+import Data.Time.Calendar (Day)
+import Data.Typeable
+import Servant.Foreign
+
+data CSharp
+
+instance HasForeignType CSharp Text a => HasForeignType CSharp Text [a] where
+    typeFor lang ftype (Proxy :: Proxy [t]) = "List<" <> typeFor lang ftype (Proxy :: Proxy t) <> ">"
+
+instance HasForeignType CSharp Text a => HasForeignType CSharp Text (Maybe a) where
+    typeFor lang ftype (Proxy :: Proxy (Maybe t)) = "Nullable<" <> typeFor lang ftype (Proxy :: Proxy t) <> ">"
+
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text () where
+    typeFor _ _ _ = "void"
+
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text Int where
+    typeFor _ _ _ = "int"
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text (Maybe Int) where
+    typeFor _ _ _ = "int?"
+
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text Text where
+    typeFor _ _ _ = "string"
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text (Maybe Text) where
+    typeFor _ _ _ = "string"
+
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text String where
+    typeFor _ _ _ = "string"
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text (Maybe String) where
+    typeFor _ _ _ = "string"
+
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text Day where
+    typeFor _ _ _ = "DateTime"
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text (Maybe Day) where
+    typeFor _ _ _ = "DateTime?"
+
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text UTCTime where
+    typeFor _ _ _ = "DateTime"
+instance {-# OVERLAPPING #-} HasForeignType CSharp Text (Maybe UTCTime) where
+    typeFor _ _ _ = "DateTime?"
+
+instance {-# OVERLAPS #-} Typeable t => HasForeignType CSharp Text t where
+    typeFor lang ftype p = pack $ show $ typeRep p
+
+getEndpoints :: (HasForeign CSharp Text api,
+                 GenerateList Text (Foreign Text api)) =>
+                Proxy api -> [Req Text]
+getEndpoints = listFromAPI (Proxy :: Proxy CSharp) (Proxy :: Proxy Text)
+
diff --git a/src/CS/JsonDotNet.hs b/src/CS/JsonDotNet.hs
new file mode 100644
--- /dev/null
+++ b/src/CS/JsonDotNet.hs
@@ -0,0 +1,255 @@
+{-# LANGUAGE ExplicitForAll #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module CS.JsonDotNet ( csForAPI
+                     , csForAPIWith
+
+                     , GenerateCsConfig(..)
+                     , def
+                     ) where
+
+import Prelude hiding (concat, lines, unlines)
+import Control.Arrow
+import Control.Lens
+import Data.ByteString (ByteString)
+import Data.ByteString.Char8 as BC (unpack)
+import Data.Char (toUpper, toLower)
+import Data.List (intercalate, concat)
+import Data.Maybe (fromJust)
+import Data.Monoid ((<>))
+import Data.Proxy
+import Data.Text as T (Text, unpack, pack)
+import Language.Haskell.Exts
+import Servant.Foreign
+import Text.Heredoc
+
+import CS.Common (CSharp, getEndpoints)
+
+data GenerateCsConfig
+    = GenerateCsConfig { namespace :: String
+                       , template ::  forall api.
+                                      (HasForeign CSharp Text api,
+                                       GenerateList Text (Foreign Text api))
+                                      => GenerateCsConfig
+                                          -> Proxy api
+                                          -> IO String
+                       , sources :: [FilePath]
+                       }
+
+def :: GenerateCsConfig
+def = GenerateCsConfig { namespace = "ServantClientAPI"
+                       , template = defTemplate
+                       , sources = []
+                       }
+
+-- | TODO : more typeable
+isNewtypeDecl :: Decl -> Bool
+isNewtypeDecl (DataDecl _ NewType _ _ _ _ _) = True
+isNewtypeDecl _ = False
+
+origType :: QualConDecl -> String
+origType (QualConDecl _ _ _ (RecDecl _ [(_, TyCon (UnQual (Ident t)))]))
+    = case t of
+        "String"  -> "System.String"
+        "Text"    -> "System.String"
+        "Int"     -> "System.Int64"
+        "Integer" -> "System.Int64"
+        t         -> error "don't supported type. "<>t
+
+usingAliasesFromFiles :: [FilePath] -> IO [(String, String)]
+usingAliasesFromFiles hss
+    = return . concat =<< mapM usingAliasesFromFile hss
+
+usingAliasesFromFile :: FilePath -> IO [(String, String)]
+usingAliasesFromFile hs = do
+  ParseOk (Module _ _ _ _ _ _ decls) <- parseFile hs
+  let xs = filter isNewtypeDecl decls
+  return $ map toTuple xs
+    where
+      toTuple (DataDecl _ NewType _ (Ident name) _ [qcon] _)
+              = (name, origType qcon)
+retType :: Req Text -> String
+retType = T.unpack . fromJust . view reqReturnType
+
+uri :: Req Text -> String
+uri req = T.unpack $ segmentsToText $ req^..reqUrl.path.traverse
+    where
+      segmentsToText :: [Segment f] -> Text
+      segmentsToText = foldr segToText ""
+      segToText :: Segment f -> Text -> Text
+      segToText (Segment (Static s)) ss
+          = "/" <> s^._PathSegment <> ss
+      segToText (Segment (Cap s)) ss
+          = "/{" <> prefix <> s^.argName._PathSegment <> "}" <> ss
+      prefix = "_"
+
+methodType :: Req Text -> String
+methodType = capitalize . BC.unpack . view reqMethod
+    where
+      capitalize :: String -> String
+      capitalize (c:cs) = toUpper c:map toLower cs
+
+methodName :: Req Text -> String
+methodName  = T.unpack . view (reqFuncName.camelCaseL)
+
+paramDecl :: Req Text -> String
+paramDecl = intercalate ", " . map help . paramInfos True
+    where
+      help :: (String, String) -> String
+      help (t, n) = t<>" "<>(prefix<>n)
+      prefix = "_"
+
+paramArg :: Req Text -> String
+paramArg = intercalate ", " . map help . paramInfos False
+    where
+      help :: (String, String) -> String
+      help (_, n) = prefix<>n
+      prefix = "_"
+
+paramInfos :: Bool -> Req Text -> [(String, String)]
+paramInfos b req = foldr (<>) mempty
+                   $ map ($ req) [ captures
+                                 , rqBody
+                                 , queryparams'
+                                 ]
+    where
+      queryparams' = map (help b) . queryparams
+          where
+            help True  = convToNullable *** (<>" = null")
+            help False = convToNullable *** id
+            -- TODO : more typeable
+            convToNullable "int" = "int?"
+            convToNullable "string" = "string"
+            convToNullable "DateTime" = "DateTime?"
+            convToNullable t = "Nullable<"<>t<>">"
+
+queryparams :: Req Text -> [(String, String)]
+queryparams req = map ((T.unpack . view argType
+                       &&&
+                        T.unpack . unPathSegment . view argName)
+                      . view queryArgName)
+                  $ req^..reqUrl.queryStr.traverse
+
+captures :: Req Text -> [(String, String)]
+captures req = map ((T.unpack . view argType &&& T.unpack . view argPath)
+                    . captureArg)
+               . filter isCapture
+               $ req^.reqUrl.path
+
+rqBody :: Req Text -> [(String, String)]
+rqBody req = maybe [] (pure . (T.unpack &&& const jsonReqBodyName))
+             $ req^.reqBody
+    where
+      jsonReqBodyName = "obj"
+
+requestBodyExists :: Req Text -> Bool
+requestBodyExists = not . null . rqBody
+
+csForAPI :: (HasForeign CSharp Text api,
+             GenerateList Text (Foreign Text api)) =>
+            Proxy api -> IO String
+csForAPI = csForAPIWith def
+
+csForAPIWith :: (HasForeign CSharp Text api,
+                 GenerateList Text (Foreign Text api)) =>
+                GenerateCsConfig -> Proxy api -> IO String
+csForAPIWith conf api = (template conf) conf api
+
+defTemplate :: (HasForeign CSharp Text api,
+                GenerateList Text (Foreign Text api)) =>
+               GenerateCsConfig -> Proxy api -> IO String
+defTemplate conf api = do
+  usingAliases <- usingAliasesFromFiles $ sources conf
+  return [heredoc|/* generated by servant-csharp */
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading.Tasks;
+
+#region type alias
+$forall (n, t) <- usingAliases
+  using ${n} = ${t};
+#endregion
+
+namespace ${namespace conf}
+{
+    class ServantClient : HttpClient
+    {
+        public ServantClient()
+        {
+            this.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+        }
+    }
+
+    public class API
+    {
+        #region fields
+        private string server;
+        #endregion
+
+        #region properties
+        #endregion
+
+        #region Constructor
+        public API(string _server)
+        {
+            this.server = _server;
+        }
+        #endregion
+
+        #region APIs
+        $forall ep <- getEndpoints api
+          $if retType ep /= "void"
+            public async Task<${retType ep}> ${methodName ep}Async(${paramDecl ep})
+          $else
+            public async Task ${methodName ep}Async(${paramDecl ep})
+          {
+              var client = new ServantClient();
+              var queryparams = new List<string> {
+                  $forall (_, qp) <- queryparams ep
+                    _${qp}.HasValue ? $"_${qp}={_${qp}.Value}" : null,
+              }.Where(e => !string.IsNullOrEmpty(e));
+              var qp= queryparams.Count() > 0 ? $"?{string.Join("&", queryparams)}" : "";
+              $if requestBodyExists ep
+                #if DEBUG
+                var jsonObj = JsonConvert.SerializeObject(_obj, Formatting.Indented);
+                #else
+                var jsonObj = JsonConvert.SerializeObject(_obj);
+                #endif
+              $if requestBodyExists ep
+                var res = await client.${methodType ep}Async($"{server}${uri ep}{qp}", new StringContent(jsonObj, Encoding.UTF8, "application/json"));
+              $else
+                var res = await client.${methodType ep}Async($"{server}${uri ep}{qp}");
+              Debug.WriteLine($">>> {res.RequestMessage}");
+              $if requestBodyExists ep
+                Debug.WriteLine($"-----");
+                Debug.WriteLine(jsonObj);
+                Debug.WriteLine($"-----");
+              Debug.WriteLine($"<<< {(int)res.StatusCode} {res.ReasonPhrase}");
+              var content = await res.Content.ReadAsStringAsync();
+              Debug.WriteLine($"<<< {content}");
+              $if retType ep /= "void"
+                return JsonConvert.DeserializeObject<${retType ep}>(content);
+              $else
+                JsonConvert.DeserializeObject(content);
+         }
+          public ${retType ep} ${methodName ep}(${paramDecl ep})
+          {
+              $if retType ep /= "void"
+                Task<${retType ep}> t = ${methodName ep}Async(${paramArg ep});
+                return t.GetAwaiter().GetResult();
+              $else
+                Task t = ${methodName ep}Async(${paramArg ep});
+                t.GetAwaiter().GetResult();
+          }
+        #endregion
+    }
+}
+|]
