블로그 이미지
Sunny's

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2012. 3. 22. 15:50 IPhone

This is the eighth iOS 5 tutorial in the iOS 5 Feast! This tutorial is a free preview chapter from our new book iOS 5 By Tutorials. Enjoy!

This is a blog post by iOS Tutorial Team member Marin Todorov, a software developer with 12+ years of experience, an independent iOS developer and the creator of Touch Code Magazine.

iOS 5 has some new built-in APIs to make it really easy to read and write JSON.

If you don’t know what JSON is, it’s a simple human readable format that is often used to send data over a network connection.

For example, if you have an array of three strings, the JSON representation would simply be:

["test1", "test2", "test3"]

If you have a Pet object with member variables name, breed, and age, the JSON representation would simply be:

{"name" : "Dusty", "breed": "Poodle", "age": 7}

It’s that simple, which is why it’s so easy and popular to use. For the full spec, which can be read in just a couple minutes, check out www.json.org.

The reason JSON is important is that many third parties such as Google, Yahoo, or Kiva make web services that return JSON formatted data when you visit a URL with a specified query string. If you write your own web service, you’ll also probably find it really easy to convert your data to JSON when sending to another party.

In this tutorial, we’ll cover how you can work with JSON in iOS 5. Keep reading to see how simple it is!

JSON and iOS 5

If you’ve had to parse JSON in your iOS apps in the past, you’ve probably used a third party library such as JSON Framework.

Well with iOS 5, needing to use a third party library for JSON parsing is a thing of the past. Apple has finally added a JSON library in Cocoa and I must say I personally like it very much!

You can turn objects like NSString, NSNumber, NSArray and NSDictionary into JSON data and vice versa super easily. And of course no need to include external libraries – everything is done natively and super fast.

In this chapter we’re going to get hands-on experience with the new native JSON support. We’re going to build a simple application which will connect to the Internet and consume JSON service from the Kiva.org web site. It will parse the data, show it in human readable format on the screen, and then build back a different JSON.

descr

Later on in the chapter we’re going to create a class category which will give you ideas how to integrate JSON support more tightly into Cocoa and your own classes. Having the possibility to turn your own classes data into JSON could really help you persist data structures online, exchange data between applications, or anything that requires your classes to be able to serialize and persist data, which can be sent over http, email, etc.

Getting Started

Open up Xcode and from the main menu choose File\New\New Project. Choose the iOS\Application\Single View Application template, and click Next. Name the product KivaJSONDemo, select iPhone for the Device family, and make sure just the Use Automatic Reference Counting checkbox is checked, click Next and save the project by clicking Create.

Let’s do a little bit of clean up first – open up ViewController.m file and replace everything inside with this :

#define kBgQueue dispatch_get_global_queue(
 DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) //1
#define kLatestKivaLoansURL [NSURL URLWithString: 
 @"http://api.kivaws.org/v1/loans/search.json?status=fundraising"] //2
 
#import "ViewController.h"
 
@implementation ViewController
 
@end

In the first line of code we define a macro that gives us back a background queue – I like having a kBgQueue shortcut for that, so I can keep my code tighter.

In the second line of code we create a macro named kLatestKivaLoansURL which returns us an NSURL pointing to this URL [http://api.kivaws.org/v1/loans/search.json?status=fundraising].

Go ahead and visit this URL in your browser if you want – you’ll see Kiva.org’s list of currently fundraising loans in JSON format. We’re going to use this API to read the list of loans, take the latest one and show the information on the screen.

Let’s make a little detour and design the application’s UI in Interface Builder real quick.

Open ViewController.xib in the Project Navigator. This app is supposed to be positive and life-changing, so we need to do something about that background! Select it and from the Utilities bar (1), make sure you have the Attributes Inspector open (2), and set the Background to a nice green color (3).

descr

Now grab a label from the Object library and drop it inside the already open view (1). Resize the label so it fits about 4 lines of text and takes almost the screen’s width (2). Then from the Attributes Inspector make the following changes: set “Background” to white, set “Lines” to “5″ (3). Click on the label to make sure it’s selected and then press Cmd+C, Cmd+V to clone the label (4). Finally arrange the two labels like on the screenshot:

descr

To polish up the interface add 3 more labels and finish the UI so it looks like this:

descr

The only thing left is to connect our labels to a couple of IBOutlets in our class. Switch to ViewController.h and add two instance variables inside the interface:

@interface ViewController : UIViewController {
    IBOutlet UILabel* humanReadble;
    IBOutlet UILabel* jsonSummary;
}

Then open up ViewController.xib again. Control-drag from “File’s owner” onto the 1st 5-line label and from the popup menu choose humanReadable.

Again while holding the “ctrl” key drag with the mouse from “File’s owner” onto the 2nd 5-line label and from the popup menu choose jsonSummary.

That concludes the project setup – we’re ready to start coding!

Parsing JSON from the Web

The first thing we need to do is download the JSON data from the web. Luckily, with GCD we can do this in one line of code! Add the following to ViewController.m:

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    dispatch_async(kBgQueue, ^{
        NSData* data = [NSData dataWithContentsOfURL: 
          kLatestKivaLoansURL];
        [self performSelectorOnMainThread:@selector(fetchedData:) 
          withObject:data waitUntilDone:YES];
    });
}

Remember how earlier we defined kBGQueue as a macro which gives us a background queue?

Well this bit of code makes it so that when viewDidLoad is called, we run a block of code in this background queue to download the contents at the Kiva loans URL.

When NSData has finished fetching data from the Internet we call performSelectorOnMainThread:withObject:waitUntilDone: so we can update the application’s UI. We haven’t written fetchedData: yet but will do so shortly.

Remember it is only OK to run a synchronous method such as dataWithContentsOfURL in a background thread, otherwise the GUI will seem unresponsive to the user.

Also, remember that you can only access UIKit objects from the main thread, which is why we had to run fetchedData: on the main thread.

Note: You might wonder why I preferred to use performSelectorOnMainThread:withObject:waitUntilDone: over dispatching a block on the main thread? It’s a personal preference really and I have two reasons:

I’m all for the greatest readability of a piece of code. For me, [self performSelectorOnMainThread:...] makes it easier to spot what’s going on in that piece of code.
I’m a symmetry freak! I find that Xcode doesn’t handle text indentation well when you use dispatch_async(), so purely visually the code is not so pleasant to look at.
You might have other preferences, so yes – if you prefer dispatch_async(dispatch_get_main_queue(), ^(){…}); go for it!

So, when the data has arrived the method fetchedData: will be called and the NSData instance will be passed to it. In our case the JSON file is relatively small so we’re going to do the parsing inside fetchedData: on the main thread. If you’re parsing large JSON feeds (which is often the case), be sure to do that in the background.

So next add the fetchedData method to the file:

- (void)fetchedData:(NSData *)responseData {
    //parse out the json data
    NSError* error;
    NSDictionary* json = [NSJSONSerialization 
        JSONObjectWithData:responseData //1
 
        options:kNilOptions 
        error:&error];
 
    NSArray* latestLoans = [json objectForKey:@"loans"]; //2
 
    NSLog(@"loans: %@", latestLoans); //3
}

This is it – the new iOS 5 JSON magic!

Basically iOS 5 has a new class named NSJSONSerialization. It has a static method called JSONObjectWithData:options:error that takes an NSData and gives you back a Foundation object – usually an NSDictionary or an NSArray depending what do you have at the top of your JSON file hierarchy.

In Kiva.org’s case at the top there’s a dictionary, which has a key with list of loans. In line 1, we get an NSDictionary from the JSON data. In line 2, we get an NSArray latestLoans which is the loans key in the top JSON dictionary.

Finally in line 3, we dump latestLoans to the console, so we’re sure everything’s OK. Hit Run and check Xcode’s console to see the result:

descr

Not bad for 3 lines of code, eh? :]

Parsing Options

I’d like to talk just a bit more about NSJSONSerialization’s JSONObjectWithData:options:error: method. It’s one of these Apple APIs which understand and do everything by themselves, but you still can configure a bit its behavior.

Notice in the code that I chose to pass for the parameter options a value of kNilOptions. kNilOptions is just a constant for 0 – I find its name very descriptive though, so I always prefer it over just the value of 0 as a method parameter.

However you can pass other values or even a bit mask of values to combine them. Have a look at what you got as options when you’re converting JSON to objects:

  • NSJSONReadingMutableContainers: The arrays and dictionaries created will be mutable. Good if you want to add things to the containers after parsing it.
  • NSJSONReadingMutableLeaves: The leaves (i.e. the values inside the arrays and dictionaries) will be mutable. Good if you want to modify the strings read in, etc.
  • NSJSONReadingAllowFragments: Parses out the top-level objects that are not arrays or dictionaries.

So, if you’re not only reading, but also modifying the data structure from your JSON file, pass the appropriate options from the list above to JSONObjectWithData:options:error:.

Displaying to the Screen

We’re going to continue by showing the latest loan information on the screen. At the end of “fetchedData:” method add these few lines of code:

// 1) Get the latest loan
NSDictionary* loan = [latestLoans objectAtIndex:0];
 
// 2) Get the funded amount and loan amount
NSNumber* fundedAmount = [loan objectForKey:@"funded_amount"];
NSNumber* loanAmount = [loan objectForKey:@"loan_amount"];
float outstandingAmount = [loanAmount floatValue] - 
  [fundedAmount floatValue];
 
// 3) Set the label appropriately
humanReadble.text = [NSString stringWithFormat:@"Latest loan: %@ 
  from %@ needs another $%.2f to pursue their entrepreneural dream",
  [loan objectForKey:@"name"],
  [(NSDictionary*)[loan objectForKey:@"location"] 
    objectForKey:@"country"],
    outstandingAmount];

The latestLoans array is a list of dictionaries, so (1) we get the first (and latest) loan dictionary and (2) we fetch few values about the loan. Finally (3) we set the text of the 1st label in the UI.

OK! Let’s have a look – hit Run and see what comes up:

descr

Of course the information you see will be different as Kiva adds loans constantly – but it’s clear we achieved what we wanted, we parsed JSON data and visualized some human readable info.

Generating JSON Data

Now let’s do the opposite. From the loan NSDictionary that we now have we’ll build some JSON data, which we will be able to send over to a server, another app, or do with it whatever else we want.

Add this code to the end of the fetchedData: method:

//build an info object and convert to json
NSDictionary* info = [NSDictionary dictionaryWithObjectsAndKeys:
  [loan objectForKey:@"name"], 
    @"who",
  [(NSDictionary*)[loan objectForKey:@"location"] 
    objectForKey:@"country"], 
    @"where",
  [NSNumber numberWithFloat: outstandingAmount], 
    @"what",
  nil];
 
//convert object to data
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:info 
  options:NSJSONWritingPrettyPrinted error:&error];

Here we build an NSDictionary called info where we store the loan information as who, where, and what in different keys and values.

Then we call dataWithJSONObject:options:error: – the opposite to the JSON API we just used before. It takes in an object and turns it into JSON data.

For the options parameter there’s only one possible value – NSJSONWritingPrettyPrinted. If you want to send the JSON over the Internet to a server use kNilOptions as this will generate compact JSON code, and if you want to see the JSON use NSJSONWritingPrettyPrinted as this will format it nicely.

So, at this point our job of turning info into JSON is finished, but we can’t be sure before we see that it is actually so. Let’s show the JSON into our second UI label. Add this final line of code to fetchedData:

//print out the data contents
jsonSummary.text = [[NSString alloc] initWithData:jsonData                                        
  encoding:NSUTF8StringEncoding];

By initializing an NSString with initWithData:encoding: we easily get the text representation of our JSON data and we show it straight inside the jsonSummary label. Hit Run and:

descr

Integrating Objects and JSON

Imagine if NSDictionary, NSArray, NSString, and NSData had methods to convert to and from JSON data – wouldn’t that be great?

Oh, but wait – we’re using it’s Objective-C, so we can actually extend foundation classes with methods of our own! Let’s do an example with NSDictionary and see how useful that could be.

Open ViewController.m, and add this category just above the @implementation:

@interface NSDictionary(JSONCategories)
+(NSDictionary*)dictionaryWithContentsOfJSONURLString:
  (NSString*)urlAddress;
-(NSData*)toJSON;
@end
 
@implementation NSDictionary(JSONCategories)
+(NSDictionary*)dictionaryWithContentsOfJSONURLString:
  (NSString*)urlAddress
{
    NSData* data = [NSData dataWithContentsOfURL:
      [NSURL URLWithString: urlAddress] ];
    __autoreleasing NSError* error = nil;
    id result = [NSJSONSerialization JSONObjectWithData:data 
      options:kNilOptions error:&error];
    if (error != nil) return nil;
    return result;
}
 
-(NSData*)toJSON
{
    NSError* error = nil;
    id result = [NSJSONSerialization dataWithJSONObject:self 
      options:kNilOptions error:&error];
    if (error != nil) return nil;
    return result;    
}
@end

As there’s nothing new that I didn’t speak about so far in this tutorial I won’t go over the code line by line.

But basically, we define 2 methods on NSDictionary: one dictionaryWithContentsOfJSONURLString: which gets an NSString with a web address (it’s often easier to work with URLs as text, not as NSURL instances), does all the downloading, fetching, parsing and whatnot and finally just returns an instance of a dictionary (or nil in case of an error) – ain’t that pretty handy?

In the category there’s also one more method – toJSON which you call on an NSDictionary instance to get JSON data out of it.

So with this category fetching JSON from the web becomes as easy as :

NSDictionary* myInfo = 
  [NSDictionary dictionaryWithContentsOfJSONURLString:
    @"http://www.yahoo.com/news.json"];

And of course on any of your NSDictionary objects you can do:

NSDictionary* information = 
  [NSDictionary dictionaryWithObjectsAndKeys: 
    @"orange",@"apple",@"banana",@"fig",nil];
NSData* json = [information toJSON];

Pretty cool and readable code. Now of course you can also extend NSMutableDictionary with the same dictionaryWithContentsOfJSONURLString: method, but in there you’ll have to pass NSJSONReadingMutableContainers as options – so hey, NSMutableDictionary could be initialized with JSON too, and it’ll hold mutable data. Cool!

Where to Go From Here?

Here is a example project with all of the code from the above tutorial.

At this point, you have hands-on experience with the awesome new iOS5 JSON reading and writing APIs, and are ready to start using this in your own apps!

Before we go though, I want to mention just few more methods from the NSJSONSerialization class.

BOOL isTurnableToJSON = [NSJSONSerialization 
  isValidJSONObject: object]

As you might guess, isValidJSONObject: tells you whether you can successfully turn a Cocoa object into JSON data.

Also I presented to you the 2 methods to read and write JSON from/to NSData objects, but you can do that also on streams – with JSONObjectWithStream:options:error: and writeJSONObject:toStream:options:error:, so do have a look at the class documentation.

If you want to keep playing around with JSON, feel free to extend the demo project with the following features:

  • Modify the demo project to use the JSON categories, like we discussed above
    Develop further JSON categories for NSArray, NSString, etc
  • Think about how cool it’d be if your classes had a toJSON method – so you can easily persist them on your web server!
  • Make an implementation on a test class to see if you can get it working!

This is an example of one of the “bonus” chapters from our new book iOS 5 By Tutorials. The bonus chapters like this one cover some of the cool but easily overlooked new APIs in iOS 5 like the new Address Book APIs, new Location APIs, new Calendar APIs, and much more, so if you want to learn more about iOS 5 check it out!

If you have any questions, comments, or suggestions, please join in the forum discussion below!

출처 : http://www.raywenderlich.com/5492/working-with-json-in-ios-5

posted by Sunny's
2011. 11. 6. 02:58 IPhone


- (void)viewDidLoad
{
    [super viewDidLoad];
 
    dispatch_async(kBgQueue, ^{
        NSData* data = [NSData dataWithContentsOfURL: 
          kLatestKivaLoansURL];
        [self performSelectorOnMainThread:@selector(fetchedData:) 
          withObject:data waitUntilDone:YES];
    });
}
- (void)fetchedData:(NSData *)responseData {
    //parse out the json data
    NSError* error;
    NSDictionary* json = [NSJSONSerialization 
        JSONObjectWithData:responseData //1
 
        options:kNilOptions 
        error:&error];
 
    NSArray* latestLoans = [json objectForKey:@"loans"]; //2
 
    NSLog(@"loans: %@", latestLoans); //3
}




NSString *country = [loan objectForKey:@"name"] ;
NSString *country = [(NSDictionary*)[loan objectForKey:@"location"] objectForKey:@"country"];

JSON Parse 객체는 SBJSON 을 써도 동일하며 멀티 항목인 경우 (NSDictionary*)로 캐스팅 하는거에 참고하세요~ ^^*

출처 : http://www.raywenderlich.com/5492/working-with-json-in-ios-5
posted by Sunny's
2011. 5. 12. 13:54 ASP.NET


REST stands for Representational State Transfer. It is an architecture designed to represent resources via standard HTTP URIs and Verbs. REST provides a uniform interface for identifying resources, manipulating resources through representations, and including metadata that can make messages self-describing. REST is not tied to any platform or technology but is done on the Web using HTTP.


The following HTTP verbs may be used when creating RESTful services:

GET - Requests a specific representation of a resource
PUT - Create or update a resoure with the supplied representation
DELETE - Delete the specified resource
POST - Submit data to be processed by the identified resource
HEAD - Similar to GET but only retrieves headers
OPTIONS - Returns the methods supported by the identified resource

In this article I'll show how to build a "Notes" (a.k.a. "reminders") RESTful WCF service and consume it using jQuery / JSON from the client. We'll see how to create the service interface, what decorations (Attributes) are required, what's required in the web.config settings, how to make the jQuery $ajax calls to the service, and how to handle the server side logic with a small SQLite database. Everything in the downloadable solution is included - you need only unzip it and it should "work out of the box".

In order to create a WCF service, you can start with a standard ASP.NET Web Application project and add a new WCF Service.

To Create a complete WCF REST service, you start with the interface. Here's mine:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Web.Script.Services;

namespace RESTFulNotes
{

    [ServiceContract]
    public interface IService1
    {
         //GetNotes: method to get all Notes. In this UriTemplate there is tag querystring item  ={tag} allows us to filter note by category name
        [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "Notes?tag={tag}")]
        [OperationContract]
        Notes FindNotes(string tag);

        [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "Notes/{ID}")]
        [OperationContract]
        Note GetNote(string ID);

        [WebInvoke(Method = "PUT", ResponseFormat = WebMessageFormat.Json, UriTemplate = "Notes/{ID}")]
        [OperationContract]
        string PutNote(Note Noteobj, string ID);

        [WebInvoke(Method = "DELETE", UriTemplate = "Notes/{ID}")]
        [OperationContract]
        void DeleteNote(string ID);
      }

    // Use a data contract as illustrated in the sample below to add composite types to service operations
    [DataContract]
    public class Note
    {
         [DataMember]
        public int ID { get; set; }
        [DataMember]
        public string Category { get; set; }
        [DataMember]
        public string Subject { get; set; }
        [DataMember]
        public string NoteText { get; set; }
    }

     [CollectionDataContract]
    public class Notes : List<Note>
    {
         public Notes() { }
        public Notes(List<Note> Notes) : base(Notes) { }
    }
}

Note that the WebInvoke decoration is the key item here. It defines the Method, the ResponseFormat, and the custom UriTemplate you want to use. With this information, the WCF runtime is able to handle everything - all you need to do is implement the methods in server-side code, and call them correctly from client script in your consumer page.

With the IService1 interface complete and all attributes correctly marked, we're now ready to implement our interface:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SQLite;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
using System.Net;
using System.ServiceModel.Activation;
using System.Web;


namespace RESTFulNotes
{
  
    [AspNetCompatibilityRequirements(RequirementsMode =AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1 : IService1
    {
         private SQLiteConnection conn;
        Service1()
        {
            conn = Global.conn;
        }
      
         #region IService1 Members

        public Notes FindNotes(string tag)
        {
            WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
            Notes notes = new Notes();
            string Sql = "SELECT * FROM NOTE WHERE CATEGORY=@TAG";
            SQLiteCommand cmd = new SQLiteCommand(Sql, conn);
             cmd.Parameters.AddWithValue("@TAG", tag);
            SQLiteDataAdapter da = new SQLiteDataAdapter(Sql, conn);
            da.SelectCommand = cmd;
            DataTable dt = new DataTable();
             da.Fill(dt);
            Note note;
             if (dt.Rows.Count > 0)
            {
                foreach (DataRow row in dt.Rows)
                {

                    note = new Note();
                    note.ID = Convert.ToInt32(row["ID"]);
                    note.Category = (string) row["Category"];
                    note.Subject = (string) row["Subject"];
                    note.NoteText = (string) row["NoteText"];
                     notes.Add(note);
                 }
             }
             return notes;
        }

         public Note GetNote(string ID)
        {
            string Sql = "SELECT * FROM NOTE WHERE ID=@ID";
            SQLiteCommand cmd = new SQLiteCommand(Sql, conn);
             cmd.Parameters.AddWithValue("@ID", int.Parse(ID));
            SQLiteDataAdapter da = new SQLiteDataAdapter(Sql, conn);
            da.SelectCommand = cmd;
            DataTable dt = new DataTable();
             da.Fill(dt);
            Note note=null;
            if (dt.Rows.Count > 0)
            {
                DataRow row = dt.Rows[0];
                note = new Note();
                note.ID = Convert.ToInt32(row["ID"]);
                note.Category = (string)row["Category"];
                note.Subject = (string)row["Subject"];
                note.NoteText = (string)row["NoteText"];
            }
            
            WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
             return note;
        }

         public string PutNote(Note  note, string ID)
        {
            String Sql = "INSERT INTO NOTE (CATEGORY,SUBJECT,NOTETEXT) VALUES(@CATEGORY,@SUBJECT,@NOTETEXT)";
            SQLiteCommand cmd = new SQLiteCommand(Sql, conn);

             cmd.Parameters.AddWithValue("@CATEGORY", note.Category);
             cmd.Parameters.AddWithValue("@SUBJECT", note.Subject);
             cmd.Parameters.AddWithValue("@NOTETEXT", note.NoteText);
             if(cmd.Connection.State ==ConnectionState.Closed)
            cmd.Connection.Open();
            cmd.ExecuteNonQuery();
            cmd.CommandText = "SELECT MAX(ID) FROM NOTE";
            var id = cmd.ExecuteScalar();
            int retval = Convert.ToInt32(id);
             cmd.Connection.Close();
            WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Created;
            return "ID=" + retval.ToString();
        }

        public void DeleteNote(string ID)
        {
            WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Found;
          // delete the database row here
         }

         #endregion
    }
}


The actual SQLite connection is defined in global.asax.cs:

public static SQLiteConnection conn;
        void Application_Start(object sender, EventArgs e)
        {
            string cestring = "Data Source=" + HttpContext.Current.Server.MapPath("~/App_Data/Notes.db") + ";version=3";
            conn = new SQLiteConnection(cestring);
        }

This ensures that we get a path to the Notes.db SQLite database file no matter how we've deployed or unzipped the app.

The web.config requirements once the service methods are all implemented is as follows:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <authentication mode="Windows" />
    <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="EndpointBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="RESTFulNotes.Service1">
        <endpoint address="" binding="webHttpBinding" contract="RESTFulNotes.IService1" behaviorConfiguration="EndpointBehavior">      
        </endpoint>
      </service>
    </services>
  </system.serviceModel>  
</configuration>

Now let's switch over to the Default.aspx page, where all the action is in client script:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="RESTFulNotes._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <script src="Scripts/JSon.js" type="text/javascript"></script>
      <script type="text/javascript">
          var Type;
          var Url;
          var Data;
          var ContentType;
          var DataType;
          var ProcessData;
          var method;
          //Generic function to call ASMX/WCF  Service
          function CallService() {
               $.ajax({
                   type: Type, //GET,POST,PUT or DELETE verb
                  url: Url, // Location of the service
                  data: Data, //Data to be sent to server
                  contentType: ContentType, // content type sent to server
                  dataType: DataType, //Expected data format from server
                  processdata: ProcessData, //True or False
                  success: function (msg) {  //On Successful service call
                      ServiceSucceeded(msg);
                  },
                  error: ServiceFailed // function When Service call fails
              });
          }

          function ServiceFailed(result) {
               alert('Service call failed: ' + result.status + '' + result.statusText);
             Type = null; Url = null; Data = null; ContentType = null; DataType = null; ProcessData = null;
          }

          function GetNote() {
              var ID = "5";
             Type = "POST";
              Url = "Service1.svc/Notes/" + ID;
               //Data = '{"ID": "' + ID + '"}';
              ContentType = "application/json; charset=utf-8";
              DataType = "json";
              ProcessData = false;
              method = "GetNote";
              CallService();
          }
          
          function FindNotes() {
             Type = "POST";
              var tag = "Chores";
              Url = "Service1.svc/Notes?tag=" + tag;
              Data = '{"tag": "' + tag + '"}';
              ContentType = "application/json; charset=utf-8";
              DataType = "json";
              ProcessData = true;
              method = "FindNotes";
              CallService();
          }

          function CreateNote() {
             Type = "PUT";
              Url = "Service1.svc/Notes/0";
              var msg2 = {  "Category" : "Chores", "Subject": "To Remember", "NoteText": "Get Milk!" };
              Data = JSON.stringify(msg2);
              ContentType = "application/json; charset=utf-8";
              DataType = "json";
              ProcessData = true;
              method = "CreateNote";
              CallService();
          }


          function ServiceSucceeded(result) {
               if (DataType == "json") {

                   if (method == "CreateNote") {
                       document.getElementById("display").innerHTML = "CREATED: " + result;
                   }
                   else if (method == "GetNote") {
                  resultObject = result.GetNoteResult;
                      var string = " ID:" + result.ID + "<br/>" + "CATEGORY: " + result.Category + "<br/>" + "SUBJECT: " + result.Subject + "<br/>NOTE: " + result.NoteText;
                       document.getElementById("display").innerHTML = string;
                   }

                    else if (method == "FindNotes") {
                    var string="";
                      resultObject = result;

                       for( result in resultObject){
                          string += " ID:" + resultObject[result].ID + "<br/>" + "CATEGORY: " + resultObject[result].Category + "<br/>" + "SUBJECT: " + resultObject[result].Subject + "<br/>NOTE: " + resultObject[result].NoteText + "<Br/>";
                       }
                        document.getElementById("display").innerHTML = string;
                  }

              }
          }

          function ServiceFailed(xhr) {
               alert("FAIL" +xhr.responseText);
               if (xhr.responseText) {
                  var err = xhr.responseText;
                   if (err)
                       error(err);
                   else
                      error({ Message: "Unknown server error." })
               }
               return;
          }

          $(document).ready(
         function () {
             //   CreateNote();
             // GetNote();
             FindNotes();
         }
         );
        
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <div id="display">    
    </div>
</asp:Content>

You can see above that I have two script tags defined, one to the google jQuery CDN, and the other to Crockford's Json.js hosted locally.

The business logic in the last script section includes a "genericized" jQuery $ajax call:

           var Type;
          var Url;
          var Data;
          var ContentType;
          var DataType;
          var ProcessData;
          var method;
          //Generic function to call ASMX/WCF  Service
          function CallService() {
               $.ajax({
                   type: Type, //GET,POST,PUT or DELETE verb
                  url: Url, // Location of the service
                  data: Data, //Data to be sent to server
                  contentType: ContentType, // content type sent to server
                  dataType: DataType, //Expected data format from server
                  processdata: ProcessData, //True or False
                  success: function (msg) {  //On Successful service call
                      ServiceSucceeded(msg);
                  },
                  error: ServiceFailed // function When Service call fails
              });
          }

The above allows us to set parameters and make service calls for any method.

I have a ServiceSucceeded function that handles display of results for various method calls, and a ServiceFailed function to show any error messages.

$(document).ready {... } is where you can experiment with whatever function you want to try.

The other functions are just "set ups" for the CallService method. I did not create a fancy jQuery UI for this as it is outside the scope of the article. Ambitious programmers will want to use the jQuery Templating mechanism to populate grids, etc with results.

You can download the fully  functional Visual Studio 2010 Solution which includes the standalone System.Data.Sqlite assembly (this is a mixed - mode assembly which has both the ADO.NET provider and the actual C++ database engine), as well as the sample Notes.db database.



출처 : http://www.eggheadcafe.com/tutorials/aspnet/b480ba4e-b59c-43d4-ac4b-2990ca19daec/restful-aspnet-wcf--jquery--json-service-with-get-post-put-and-delete.aspx


posted by Sunny's
2010. 6. 30. 10:11 JQUERY

참고 URL : http://www.malsup.com/jquery/form/#ajaxSubmit

The following code controls the HTML form beneath it. It uses ajaxSubmit to submit the form.

// prepare the form when the DOM is ready 
$(document).ready(function() { 
    var options = { 
        target:        '#output2',   // target element(s) to be updated with server response 
        beforeSubmit:  showRequest,  // pre-submit callback 
        success:       showResponse  // post-submit callback 
 
        // other available options: 
        //url:       url         // override for form's 'action' attribute 
        //type:      type        // 'get' or 'post', override for form's 'method' attribute 
        //dataType:  null        // 'xml', 'script', or 'json' (expected server response type) 
        //clearForm: true        // clear all form fields after successful submit 
        //resetForm: true        // reset the form after successful submit 
 
        // $.ajax options can be used here too, for example: 
        //timeout:   3000 
    }; 
 
    // bind to the form's submit event 
    $('#myForm2').submit(function() { 
        // inside event callbacks 'this' is the DOM element so we first 
        // wrap it in a jQuery object and then invoke ajaxSubmit 
        $(this).ajaxSubmit(options); 
 
        // !!! Important !!! 
        // always return false to prevent standard browser submit and page navigation 
        return false
    }); 
}); 
 
// pre-submit callback 
function showRequest(formData, jqForm, options) { 
    // formData is an array; here we use $.param to convert it to a string to display it 
    // but the form plugin does this for you automatically when it submits the data 
    var queryString = $.param(formData); 
 
    // jqForm is a jQuery object encapsulating the form element.  To access the 
    // DOM element for the form do this: 
    // var formElement = jqForm[0]; 
 
    alert('About to submit: \n\n' + queryString); 
 
    // here we could return false to prevent the form from being submitted; 
    // returning anything other than false will allow the form submit to continue 
    return true

 
// post-submit callback 
function showResponse(responseText, statusText, xhr, $form)  { 
    // for normal html responses, the first argument to the success callback 
    // is the XMLHttpRequest object's responseText property 
 
    // if the ajaxSubmit method was passed an Options Object with the dataType 
    // property set to 'xml' then the first argument to the success callback 
    // is the XMLHttpRequest object's responseXML property 
 
    // if the ajaxSubmit method was passed an Options Object with the dataType 
    // property set to 'json' then the first argument to the success callback 
    // is the json data object returned by the server 
 
    alert('status: ' + statusText + '\n\nresponseText: \n' + responseText + 
        '\n\nThe output div should have already been updated with the responseText.'); 


posted by Sunny's
2009. 12. 9. 09:40 Ajax

Json -> xml
xml - > Json



<script type="text/javascript" src="inc/xml2json.js"></script>
<script type="text/javascript" src="inc/json2xml.js"></script>

<script type="text/javascript">
  /**
   * @file action
   * @brief Javascript Action 2.0
   *
   * registered date 20091209
   * updated date 20091209
   * programmed by Yong Sun. Choi. (최용선)
   * http://sunnydev.tistory.com
   */
  var m_xml = '<Pages><page><no>1</no><status>1</status></page><page><no>2</no><status>2</status></page></Pages>';

 // xmldom 로드
  var dom = parseXml(m_xml);

  // dom -> json 변형 : 문자열인 상태
  var json = xml2json(dom, "");

  // json 객체화
  json = eval("(" + json + ")");

 document.writeln(json.Pages.page[0].status);

 json.Pages.page[0].status = 5;

 document.writeln(json.Pages.page[0].status);

  // json -> dom 변형 : 문자열인 상태
  var data = json2xml(json, null);
  alert(data);


  function parseXml(xml) {
      var dom = null;
      if (window.DOMParser) {
          try {
              dom = (new DOMParser()).parseFromString(xml, "text/xml");
          }
          catch (e) { dom = null; }
      }
      else if (window.ActiveXObject) {
          try {
              dom = new ActiveXObject('Microsoft.XMLDOM');
              dom.async = false;
              if (!dom.loadXML(xml)) // parse error ..
                  window.alert(dom.parseError.reason + dom.parseError.srcText);
          }
          catch (e) { dom = null; }
      }
      else
          alert("oops");
      return dom;
  }





posted by Sunny's
2009. 9. 29. 11:27 Ajax
posted by Sunny's
2009. 9. 29. 10:44 Ajax

jQuery 플러그인 중에 autocomplete가 있는데, 이 녀석은 배열을 사용하기 때문에 URL에서 넘어온 JSON 데이터를 제대로 인식하지 못할 뿐더러, JSON을 인식한다쳐도 스프링 JSONView가 만들어주는 JSON에서 모델이름으로 값을 꺼내와야 하는데, 그런 장치가 전혀 없기 때문에... 뜯어 고쳤습니다.

새로운 option을 추가하고, Ajax 요청을 보내는 부분을 고치고, Ajax로 받아온 데이터를 파싱하는 부분을 수정했더니 잘 동작했습니다. 스프링 JsonView에 특화된 jQuery 자동완성 플러긴으로 보면 되겠군요.


목록에 보여줄 형태를 옵션으로 지정해 줄 수 있어서 이름 + " " + 이메일 형태를 보여주도록 설정했습니다. 넓이도 조정할 수 있으니.. 글자가 잘리지 않게 너비를 조정할 수도 있겠네요.

자세한 옵션은 http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

여러가지 사용 예제는 http://jquery.bassistance.de/autocomplete/demo/

모든 옵션을 확인하진 않았지만, 대부분의 옵션(목록 갯수 설정, 검색할 때 필요한 최소 글자 수, 등등등)이 제대로 동작했습니다.

기본으로 화살표 이동도 되고, 캐싱도 지원해주니.. 이 정도면 썩 괜찮으 듯 합니다. 선택이 했을 때는 선택한 데이터 row를 가지고 function을 실행할 수 있게 해주는데, 그걸 이용해서 입력한 값 주변에 기타 정보를 출력하도록 만들 수 있었습니다.

그러나 한글값을 넘겨봤더니 깨지더군요. 그래서 encodeURIComponent()로 값을 감싸서 UTF-8로 보냈습니다. 그런 다음 컨트롤러에서 받아서 디코딩을 했죠.

keyword = URLDecoder.decode(keyword,"UTF-8");

디코딩 하는 방법은 성윤이가 도와줬습니다. 흠.. 사부님 말씀으로는 이렇게 UTF-8로 인코딩/디코딩 하지 않고도 처리할 수 있는 방법이 있는 것 같은데.. 일단 거기까진 신경쓰지 않기로 했습니다. 지금도 충분히 어지러우니까요. @_@

라이선스가 GPL하고 mit 라이선스던데 소스를 공개해야 라이선스를 위반하지 않는거 아닌지 모르겠네요. 대충 고친건데.. 흠..

이젠 테스트 데이터를 왕창 넣고 확인해 봐야겠습니다.
posted by Sunny's
prev 1 next