MUSGO / Servidor de formulários do InfoPath (InfoPath 2007) desempenho de lista drop-down

Categoria adicional: InfoPath

Resumo: Um InfoPath 2007 formulário implantado para um servidor do MOSS fornece uma lista suspensa de fornecedores amarrado a uma lista personalizada de musgo. Ao selecionar um fornecedor, regras atribuir valores de campo para um punhado de campos de texto, como o nome do representante de vendas, Endereço, cidade, Estado, postal e telefone. O desempenho é horrível. Notamos que o desempenho fica pior (de uma forma não-linear) para cada campo adicional actualizamos assim. Ou seja, Se nós apenas atualizar o nome do representante de vendas, é preciso [x] quantidade de tempo. Se nós actualizamos o representante de vendas, Address1, Endereço2, cidade, Estado, zip, é preciso 10 vezes mais.

Solução: Escrever um serviço web (código de exemplo pode ser encontrado here) Isso é passado em nome de um vendedor e ele volta retorna os detalhes do fornecedor. Em seguida, atribuir os campos desta forma. Embora isto pareça demasiado lento, Não houve diferença perceptível no desempenho quando nós atribuído 1 campo versus 8 campos. Como um bônus adicionado, os usuários obtêm um fresco "em contato com o servidor" Cylon efeito enquanto eles esperam o formulário para invocar e consumir os resultados de serviço.

MUSGO: Ocorreu uma exceção. (Exceção de HRESULT: 0x 80020009 (DISP_E_EXCEPTION))

ATUALIZAÇÃO: Nunca determinamos a causa raiz desse problema, e ele nunca a superfície novamente.

Notamos durante a implementação de um desenvolvimento local que de repente, dois usuários não conseguem acessar um conjunto de sites. Essas contas podem autenticar para o site principal, mas ao tentar acessar um determinado conjunto de sites, é só pegar uma tela em branco. Sem erros exibidos, apenas uma página em branco em branco.

Nós faça logon como um administrador de coleção do site e tente adicionar um desses utilizadores como um administrador de site e desta vez, após pressionar "OK", Recebemos esta mensagem:

Ocorreu uma exceção. (Exceção de HRESULT: 0x 80020009 (DISP_E_EXCEPTION))

Passamos algum tempo pesquisando sobre isso e, infelizmente,, não veio com nada de útil. Havia algumas mensagens no log de diagnóstico, mas era difícil exatamente correlacioná-las com esse problema.

No final, a exclusão de sites e recriados e que resolvemos isso.

Se eu descobrir o que causou isso no futuro, Vou atualizar este post.

MUSGO: Iterar em listas personalizadas e retornando dados filtrados ao InfoPath

Cenário de negócios:

Fornecer um método que permite aos usuários enter requisições de compra precisas rapidamente.

Problema de negócios:

O cliente faz negócios com vários fornecedores de cem.

Fornecedores são "tipo" específicos. Isso significa que um fornecedor vende equipamentos de informática (EG. Dell) ou material de escritório (EG. Grampos).

Como podemos ativar os usuários finais que criar compra requisições selecionar um fornecedor válido?

Solução de negócios:

Diferenciar fornecedores no sistema por meio do "tipo".

Habilitar usuários selecionar o tipo de"" do produto e, em seguida, fornecer um conjunto filtrado de fornecedores adequados.

Solução técnica:

Foi concebido um formulário do InfoPath que permite aos usuários para entrar on-line Compre requisições.

Duas listas de seleção do InfoPath Controlaram seleção de fornecedor. Primeira, o usuário seleciona um tipo de"compra". Isso limita uma segunda lista de seleção para conter apenas os fornecedores que vendem para esse tipo de compra. Este é uma clássica suspensa em cascata.

Fornecedores são armazenadas em uma lista personalizada de MOSS com colunas personalizadas para atributos como o nome do fornecedor, endereço e especialmente "tipo".

Implementar um serviço da web para um cliente do InfoPath consumir que itera através da lista de fornecedores personalizado, retornando somente fornecedores correspondência um "tipo" fornecido.

Chamar o serviço web através do formulário do InfoPath.

Lições aprendidas:

  • Primeira, parece necessário ir esta rota. Eu teria preferido fazer a filtragem totalmente no InfoPath e não criar qualquer funcionalidade do serviço da web aqui. No entanto, servidor de formulários não fornece a capacidade de filtragem necessária. Podemos colocar uma regra para um tipo"" lista de seleção no formulário tipo de reabrir a consulta fornecedor, mas nós não podemos fazê-lo funcionar corretamente. Por conseguinte, era necessário implementar o serviço da web.
  • Este é uma clássico "em cascata lista de seleção" problema no InfoPath faz mundo servidor e há muitos bons exemplos lá fora que explicam como resolver isso.
  • Um valor em branco para uma coluna na lista fornecedor não retornará um seqüência vazia quando referenciado como este: initItem["Nome do fornecedor"]. Em vez disso, Retorna um valor nulo.

Algumas outras notas:

  • Posso devolver uma matriz[] de fornecedores porque eu tive alguma dificuldade para retornar um ArrayList. O InfoPath foi reclamando sobre isso e eu não tenho o tempo ou a inclinação para lutar sobre ele. Isso, É claro, coloca um limite artificial sobre o número total de fornecedores. Ele também me obrigou a implementar uma guarnição() método na matriz porque eu odeio a idéia de voltar volta 100 de fornecedores nulos. O InfoPath não se importa, mas atormentado em mim. (Mais uma vez, Isso foi mais fácil do que brigando InfoPath por ArrayLists).
  • Implementei um GetSpecificVendorByName() função bem, que pode ser instrutivo.

O código:

usando Sistema;
usando System. Web;
usando System.Web.Services;
usando Protocols;
usando Microsoft. SharePoint;
usando System. Configuration;

/// <Resumo>
///
Serviço de fornecedor: Fornece serviços de fornecedores relacionados ao que hoje são consumidos por um formulário de cliente do infopath.
///
/// História:
/// ——–
/// 07/24/07: Inicial de codificação, Paul J. Gavin da Conchango.
///
/// </Resumo>
[WebService(Namespace = "http://www.Conchango.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
público Classe VendorService : System.Web.Services.WebService
{

/// <Resumo>
/// Representa um fornecedor de uma lista do sharepoint personalizado mantido por Luis.
/// </Resumo>
público Classe Fornecedor
{
público Fornecedor() { }

público Fornecedor(SPItem initItem)
{
se (! (initItem["Nome do fornecedor"] == nulo)) Nomefornecedor = initItem["Nome do fornecedor"].ToString();
se (! (initItem["Endereço 1"] == nulo)) VendorAddress1 = initItem["Endereço 1"].ToString();
se (! (initItem["Endereço 2"] == nulo)) VendorAddress2 = initItem["Endereço 2"].ToString();
se (! (initItem["Cidade"] == nulo)) VendorCity = initItem["Cidade"].ToString();
se (! (initItem["VendorPhone"] == nulo)) VendorPhone = initItem["VendorPhone"].ToString();
se (! (initItem["PurchaseType"] == nulo)) VendorType = initItem["PurchaseType"].ToString();
se (! (initItem["Estado"] == nulo)) VendorState = initItem["Estado"].ToString();
se (! (initItem["Zip"] == nulo)) VendorZip = initItem["Zip"].ToString();
se (!(initItem["Fax"] == nulo)) VendorFax = initItem["Fax"].ToString();
se (!(initItem["SalesRepName"] == nulo)) VendorSalesRepName = initItem["SalesRepName"].ToString();

VendorItemId = initItem.ID; // ID exclusiva mantida através de musgo.
}

público int VendorItemId;
público Cadeia de caracteres VendorName;
público Cadeia de caracteres VendorAddress1;
público Cadeia de caracteres VendorAddress2;
público Cadeia de caracteres VendorCity;
público Cadeia de caracteres VendorState;
público Cadeia de caracteres VendorZip;
público Cadeia de caracteres VendorPhone;
público Cadeia de caracteres VendorType;
público Cadeia de caracteres VendorSalesRepName;
público Cadeia de caracteres VendorFax;
}

público VendorService () {

//Descomente a linha a seguir se usando componentes concebidos
//InitializeComponent();
}

privada Fornecedor[] GenerateTestVendors()
{
Fornecedor[] Resultados;
Resultados = Novo Fornecedor[100];

Fornecedor v;
v = Novo Fornecedor();
v.VendorAddress1 = "v1_address1";
v.VendorAddress2 = "v1_address2";
v.VendorCity = "v1_city";
v.VendorName = "v1_vendorname";
v.VendorPhone = "v1_vendorphone";
v.VendorState = "v1_st";
v.VendorType = "v1_type";
v.VendorZip = "v1_zip";

Resultados[0] = v;

v = Novo Fornecedor();

v.VendorAddress1 = "v2_address1";
v.VendorAddress2 = "v2_address2";
v.VendorCity = "v2_city";
v.VendorName = "v2_vendorname";
v.VendorPhone = "v2_vendorphone";
v.VendorState = "v2_st";
v.VendorType = "v2_type";
v.VendorZip = "v2_zip";

Resultados[1] = v;

v = Novo Fornecedor();
v.VendorAddress1 = "v3_address1";
v.VendorAddress2 = "v3_address2";
v.VendorCity = "v3_city";
v.VendorName = "v3_vendorname";
v.VendorPhone = "v3_vendorphone";
v.VendorState = "v3_st";
v.VendorType = "v3_type";
v.VendorZip = "v3_zip";

Resultados[2] = v;

Voltar Resultados;

}

[WebMethod]
público Fornecedor GetSpecificVendorById(int vendorId)
{
Cadeia de caracteres SpVendorSiteName; // Nome do site do musgo real que hospeda a lista personalizada de fornecedores.
Cadeia de caracteres SpVendorListName; // Nome da lista de musgo real contendo fornecedores.

SpVendorSiteName = ConfigurationSettings.AppSettings["VendorListHostingSite"].ToString();
SpVendorListName = ConfigurationSettings.AppSettings["VendorList"].ToString();

usando (SPSite t: Microsoft.SharePoint.SPSite local = Novo SPSite t: Microsoft.SharePoint.SPSite(SpVendorSiteName))
{

usando (SPWeb Web = site. OpenWeb())
{

SPList t: Microsoft.SharePoint.SPList currentList = web. Listas de[SpVendorListName];

SPItem specificItem = currentList.Items[vendorId];

Voltar Novo Fornecedor(specificItem);

} // usando spweb web = site.openweb()
} // usando spsite site = new spsite("http://localhost/mizuho")

}

[WebMethod]
// Pressupõe que o nome do fornecedor é único, de uma perspectiva de negócios
público Fornecedor GetSpecificVendorByVendorName(Cadeia de caracteres Nomefornecedor)
{
Cadeia de caracteres SpVendorSiteName; // Nome do site do musgo real que hospeda a lista personalizada de fornecedores.
Cadeia de caracteres SpVendorListName; // Nome da lista de musgo real contendo fornecedores.

SpVendorSiteName = ConfigurationSettings.AppSettings["VendorListHostingSite"].ToString();
SpVendorListName = ConfigurationSettings.AppSettings["VendorList"].ToString();

usando (SPSite t: Microsoft.SharePoint.SPSite local = Novo SPSite t: Microsoft.SharePoint.SPSite(SpVendorSiteName))
{
usando (SPWeb Web = site. OpenWeb())
{

SPList t: Microsoft.SharePoint.SPList currentList = web. Listas de[SpVendorListName];

foreach (SPItem vendorItem em currentList.Items)
{
se (vendorItem["Nome do fornecedor"] == nulo) continuar;

se (vendorItem["Nome do fornecedor"].ToString().É igual a(Nomefornecedor))
Voltar Novo Fornecedor(vendorItem);
}

Fornecedor v = Novo Fornecedor();
v.VendorPhone = "não foi encontrado: " + Nomefornecedor;

Voltar v;

Voltar nulo;

} // usando spweb web = site.openweb()
} // usando spsite site = new spsite("http://localhost/mizuho")

} // Método

[WebMethod]
público Fornecedor[] GetVendorsOfType (Cadeia de caracteres filterType)
{

Cadeia de caracteres SpVendorSiteName; // Nome do site do musgo real que hospeda t
lista personalizada de fornecedores.
Cadeia de caracteres SpVendorListName; // Nome da lista de musgo real contendo fornecedores.

SpVendorSiteName = ConfigurationSettings.AppSettings["VendorListHostingSite"].ToString();
SpVendorListName = ConfigurationSettings.AppSettings["VendorList"].ToString();

Fornecedor[] Resultados;
int vendorIndex = 0;
Resultados = Novo Fornecedor[1000];

// Inicializar a lista com uma mensagem amigável padrão.
Fornecedor v = Novo Fornecedor();
v.VendorName = "Selecione um tipo de fornecedor para preencher essa lista.";
Resultados[0] = v;

// Converter o filtro em minúsculas para mais fácil comparação de seqüência de caracteres mais tarde.
filterType = filterType.ToLower();

// Se o tipo de filtro passado é "teste", gerar alguns dados simples.
#região Tipo de filtro = "teste"
se (filterType Equals.("teste"))
Voltar GenerateTestVendors();
#endregion

se (verdadeiro)
{
usando (SPSite t: Microsoft.SharePoint.SPSite local = Novo SPSite t: Microsoft.SharePoint.SPSite(SpVendorSiteName))
{
usando (SPWeb Web = site. OpenWeb())
{

v = nulo;

SPList t: Microsoft.SharePoint.SPList currentList = web. Listas de[SpVendorListName];

// Percorrer todos os itens na lista de fornecedores.
foreach (SPItem vendorItem em currentList.Items)
{

Cadeia de caracteres lowerVendorType;

lowerVendorType = vendorItem["PurchaseType"].ToString().ToLower();
lowerVendorType = lowerVendorType.Substring(3);

se (É igual a lowerVendorType.(filterType))
{
Resultados[vendorIndex ] = Novo Fornecedor(vendorItem);
}
} // Iterando através de todos os fornecedores na lista


Voltar TrimVendorArray(vendorIndex, Resultados);
// retornar resultados;

} // usando spweb web = site.openweb()
} // usando spsite site = new spsite("http://localhost/mizuho")

} // Se for verdade

Voltar nulo;
}

privada Fornecedor[] TrimVendorArray(int newSize, Fornecedor[] originalVendorArray)
{
Fornecedor[] trimmedArray;

se (newSize = = 0) newSize = 1;
trimmedArray = Novo Fornecedor[newSize];

int currentCounter = 0;

para (currentCounter = 0; currentCounter < newSize; currentCounter )
{
trimmedArray[currentCounter] = originalVendorArray[currentCounter];
}

Voltar trimmedArray;

}
}

MUSGO: Observações sobre o InfoPath depuração

Mensagens de erro de servidor de formulário do InfoPath são enganosas.

Durante o desenvolvimento de um formulário do InfoPath, Gostaria de enviar uma mensagem para o servidor do MOSS e acessar o formulário. A forma iria começar a carregar e então gerar uma mensagem de erro enganosa, apontando-me para o log de eventos do windows para obter detalhes. Na verdade, nenhuma mensagem foi escrita para o log de eventos do windows. Prefiro, a mensagem foi enviada para o log de diagnóstico do MOSS ascii. Você pode rastrear isso através da administração de serviços centrais.

Você precisa ser rápido em seus pés. MOSS gosta de escrever para o arquivo de log, freqüentemente e:. Isto pode ser aparado mas o log padrão escrevendo o comportamento é "tudo o mais rápido possível".

MUSGO: Atualizando uma lista personalizada

Há muitos bons exemplos de atualizar listas personalizadas através do SDK. Aqui está mais um.

Problema de negócios: Formulário do InfoPath foi concebido que permite aos usuários para entrar on-line compra requisições. Requisição de PO números devem ser seqüência tradicional com base em valores inteiros e calculados automaticamente.

Solução de negócios: Criar uma lista personalizada de musgo contendo duas colunas: "ControlField" e "ControlValue". A coluna de valor contém o próximo número de requisição de compra. Observe que o genérico "controle" Convenção de nomenclatura prevê campos de controle futuras que podem ser usados conforme necessário.

Solução técnica: Criar um web service acessado pelo cliente do InfoPath. O serviço da web retorna para o próximo número de requisição de compra e atualiza o valor da lista.

Lições aprendidas:

  • Ao adicionar esse serviço web como uma fonte de dados para o formulário do InfoPath, Achei necessário para convertê-lo para um udc e armazená-lo em uma biblioteca de conexão de dados.
  • Eu também achei necessário para ativar os scripts de domínio cruzado através de administração de serviços centrais // gerenciamento de aplicativos // configuração do servidor de forma.
  • A primeira vez que o formulário tentou acessar o serviço web, demora um pouco e de vez em quando, seria o tempo. Eu brincava com as configurações em configuração do servidor para expandir a forma de configurações de tempo limite e que pareceu ajudar.

O código:

usando Sistema;
usando System. Web;
usando System.Web.Services;
usando Protocols;
usando Microsoft. SharePoint;
usando System. Configuration;

[WebService(Namespace = "http://www.Conchango.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
público Classe PoService : System.Web.Services.WebService
{
público PoService () {

//Descomente a linha a seguir se usando componentes concebidos
//InitializeComponent();
}

/// <Resumo>
/// Obter o número de PO a próxima da lista do sharepoint po número controle.
/// Incrementar o número de PO nessa lista.
/// </Resumo>
/// <Retorna></Retorna>
[WebMethod]
público Cadeia de caracteres GetNextPoNumber()
{
Cadeia de caracteres SpPoControlSiteName; // Nome do site do musgo real que hospeda a lista de controle de PO.
Cadeia de caracteres SpPoControlListName; // Nome da lista de musgo real que contém o controle de Po.

SpPoControlSiteName = ConfigurationSettings.AppSettings["PoControlListHostingSite"].ToString();
SpPoControlListName = ConfigurationSettings.AppSettings["PoControlList"].ToString();

Cadeia de caracteres nextPoReqNumber = "xyzzy";

usando (SPSite t: Microsoft.SharePoint.SPSite local = Novo SPSite t: Microsoft.SharePoint.SPSite(SpPoControlSiteName))
{
usando (SPWeb Web = site. OpenWeb())
{

SPList t: Microsoft.SharePoint.SPList currentList = web. Listas de[SpPoControlListName];

foreach (SPItem controlItem em currentList.Items)
{

se (((Cadeia de caracteres)controlItem["ControlField"]).É igual a("NextPoNumber"))
{
nextPoReqNumber = (Cadeia de caracteres)controlItem["ControlValue"];

int int_nextPoReqNumber;
int_nextPoReqNumber = Converter.ToInt32(nextPoReqNumber);

int_nextPoReqNumber ;

controlItem["ControlValue"] = int_nextPoReqNumber;
controlItem.Update();
}

} // Localização de, ler e atualizar o número da OC na lista.


} // usando spweb web = site.openweb()
} // usando spsite site = new spsite("http://localhost/mizuho")

Voltar nextPoReqNumber;

}
}